2011-01-07 5 views
1

나는 간단한 태깅 시스템 (PHP에서 장난)를 구현하기 위해 노력하고있어 같은 값 ... 내가 필요한 스레드, 저자를 얻기 위해 다음과 같은 SQL 명령을 사용얻기 GROUP_CONCAT의 개별 값

및 관련 태그 그것과 함께 :

$thread = select_Query("SELECT thread.title, thread.id as t_id, 
         thread.content, author.username, author.id as a_id, 
         GROUP_CONCAT(DISTINCT tags.name ORDER BY tags.name DESC SEPARATOR ',') AS tags 
         FROM thread JOIN thread_tags ON thread.id = thread_tags.thread_id 
         JOIN tags ON thread_tags.tag_id = tags.id 
         INNER JOIN author on author.id = thread.author_id 
         WHERE thread.id = $id", $link); 

위에서 볼 수 있듯이 GROUP_CONCAT을 사용하고 있습니다. 이것은 잘 작동하지만, 이렇게하면 태그가 모두 하나의 변수에 나타나고 사용할 수 있다는 것을 알고 있습니다. $pieces = explode(",", $thread['tags]); 그러나 다른 방법이 있습니까? 태그는 구분하기 쉽기 때문에 좀 더 복잡한 내용 (예 : 구분 기호가 포함 된 항목)이 있기 때문에 요청하는 중입니다. 이름

ID :

스레드 : 아이디, 내용, 제목,

thread_tags author_id :

내 데이터베이스 스키마는 다음과 아이디, tag_id을

태그를 thread_id

+1

태그에 구분 기호가 포함 된 이유는 무엇입니까? 나는 프로그램 자체가 그것을 태그 분리로 간주하고 그에 따라 처리해야한다고 생각할 것이다. –

+1

태그가 아니라 태그가 스레드와 일대일 관계를 가질 수있는 다른 태그가있을 수 있습니다. "태그는 분리가 쉽지만 (예 : 구분 기호가 포함 된 것) 복잡한 경우가 있습니다." 그러나 부분은 더 복잡한 것을 말합니다. – eddienotizzard

+0

이 게시물에 group_concat에 대한 몇 가지 힌트가 있습니다. http://stackoverflow.com/questions/452357/mysql-group-concat-escaping –

답변

1

단일 셀에 여러 값을 입력하지 마십시오. 이것은 SQL이 사용되도록 설계된 방법이 아니며 분리 기호가 값 중 하나로 나타나면 문제가 발생할 수 있음을 올바르게 지적했기 때문입니다.

다행히도 쿼리를 다시 작성하여이를 해결할 수있는 방법이 있습니다. 해결 방법은 셀에 여러 값 대신 여러 행을 반환하는 것입니다. 효과적으로 을 정규화하여 결과 세트입니다. 대신 다른 말로

:

1 tag_1,tag_2,tag_3 
2 tag_2,tag_4,tag_5 

이를 수행

1 tag_1 
1 tag_2 
1 tag_3 
2 tag_2 
2 tag_4 
2 tag_5 

순진 불필요하게 대역폭을 낭비 할 수있는 다른 컬럼에 대해 같은 값을 중복 될 수 있습니다 이렇게 해당 열에 많은 데이터가 포함될 수 있습니다. 이 문제에 대한 해결책은 두 개의 쿼리를 사용하는 것입니다. 대신 다른 말로

:

1 foo bar tag_1 
1 foo bar tag_2 
1 foo bar tag_3 
2 baz qux tag_2 
2 baz qux tag_4 
2 baz qux tag_5 

는이 작업을 수행 :

Result 1: 
1 foo bar 
2 baz qux 

Result 2: 
1 tag_1 
1 tag_2 
1 tag_3 
2 tag_2 
2 tag_4 
2 tag_5 

지금 당신의 결과 집합은 정상적인 형태이다. 또한 결과가 이미 구별되어 DISTINCT 연산을 실행할 필요가 없습니다.실제로 이러한 두 개의 쿼리는 원본 데이터베이스 테이블과 훨씬 더 가깝게 일치하므로 쿼리가 훨씬 간단 해지고 더 빠르게 실행될 수 있습니다.

+0

나는 기본적으로 정확히 이렇게 말한 답변을 작성했습니다. – araqnid

+0

그는 이미이 일을하고 있습니다. 그의 질문을보세요. 그것의 그룹 concat, 그래서 그는 모든 단일 행에 대한 스레드 제목, 내용 등을 복제 결과 집합을 가지고 있지 않습니다. – profitphp

+0

@profitphp : 나는 당신이 오해했다고 생각합니다. 그는 여러 값을 하나의 셀에 채워 행을 복제하는 문제를 해결하려고 노력했습니다. "작동"하는 동안, "SQL 방식"이 아닙니다. 나는 당신이 모든 대답을 아주 조심스럽게 읽을 필요가 있다고 생각합니다. 처음에는 대답의 첫 부분만을 적용 할 필요가 있을지 모르지만 일단 그렇게하면 그는 또한 두 번째 대답을 적용 할 필요가 있음을 알게 될 것입니다. 질의와 결과가 화면에 표시되면 이것을 보는 것이 훨씬 쉬울 것이지만, 상상 만하면됩니다. 상상하기 쉽도록 예제를 제공했습니다. –

1

대부분의 태깅 시스템에는 태그에서 어떤 문자를 사용할 수 있거나 가질 수 없는지에 대한 고정 된 요구 사항 집합이 있습니다. 태그에 ,자를 허용하지 않을 수 있으며 정상적으로 작동합니다.

2

GROUP_CONCAT이 사용하는 구분 기호를 태그에 표시되지 않는 항목 ('|')으로 변경할 수 있습니다. 캐릭터.

GROUP_CONCAT(DISTINCT tags.name ORDER BY tags.name DESC SEPARATOR '|') 

또한 태그 필드의 유효성을 검사하고 구분 기호가 없는지 확인하십시오.