2012-09-20 2 views
0

테이블 왼쪽은 (간체)입니다 :

id 
name (ex:Bob) 
tags (ex:1,4,6) 

오른쪽 테이블은 다음과 같습니다

id 
tag (ex:Sailing) 

내가 왼쪽 테이블의 결과를 얻으려면 같은 :

row 1: 
    name: Bob 
    tags: Sailing,Snowboard,... 

내가 가진 가장 가까운이 있었다 :

SELECT `name`, GROUP_CONCAT(`right`.`tag`) AS tags 
FROM (`left`) 
LEFT OUTER JOIN `right` ON `right`.`id` IN(left.tags) 
ORDER BY `name` asc 

하지만이 때문에 GROUP_CONCAT() 때문에 하나의 행만 표시됩니다. 그것 없이는 모든 결과를 쉼표로 구분 된 목록의 첫 번째 태그로만 제공합니다. 나는 내가 가까이 있다는 것을 압니다.하지만 저는 이것에 너무 많은 시간을 보내고 있습니다. 어떤 도움을 주셔서 감사합니다.

나는 그것을 만들기 위해 행 (id, left_id, right_id)을 포함 할 수있는 세 번째 테이블 left_right를 만들 수 있음을 알고 있지만이를 피하고 싶습니다.

+0

'tags'는 정수 필드입니까? (당신은 다른 태그들을 가진 여러 개의 Bob 행들을 가질 수 있습니까?) – LSerni

+3

당신은 그것을 피할 수 없습니다, 그것은 미래에 훨씬 더 복잡해질 것입니다. 관계형 데이터베이스를 사용하고 있다면 관계형 데이터베이스를 올바르게 사용하십시오. 세 번째 테이블을 만들어야합니다. – kapa

+0

tags는 쉼표로 구분 된 숫자가있는 VARCHAR입니다. 모든 태그가있는 "Bob"행이 하나뿐입니다. 나는 당신이 bažmegakapa와 완전히 동의한다. 특히 사용자로부터 태그를 삭제하고자한다면 bažmegakapa에 동의한다. 그러나 나는 데이터베이스 삽입을 코딩하는 사람과 함께 일하는 다른 사람이 mysql에 그렇게 좋지 않다. 나는 그를 간단하게하려고 노력하고있다. – NaturalBornCamper

답변

1

우선 bažmegakapa는 정확하고 더 많이 말했습니다. 설명 된 설정을 올바르게 이해했다면 이미 상당한 공간 (및 성능)을 낭비하고있는 것입니다.

CREATE TABLE pleft (id integer, name varchar(20), tags integer); 
CREATE TABLE pright (id integer, tag varchar(20)); 

INSERT INTO pleft VALUES (1, 'Bob', 1), (9, 'Bob', 4), (15, 'Bob', 6); 
INSERT INTO pleft VALUES (2, 'Ann', 1), (3, 'Joe', 4), (4, 'Joe', 6); 

INSERT INTO pright VALUES (1, 'Sailing'), (4, 'Snowboarding'), (6, 'Skiing'); 


SELECT pleft.name, GROUP_CONCAT(pright.tag) 
    FROM pleft JOIN pright ON (pleft.tags = pright.id) 
    GROUP BY pleft.name ORDER BY pleft.name; 

+------+-----------------------------+ 
| name | GROUP_CONCAT(pright.tag) | 
+------+-----------------------------+ 
| Ann | Sailing      | 
| Bob | Sailing,Skiing,Snowboarding | 
| Joe | Snowboarding,Skiing   | 
+------+-----------------------------+ 

을 ...하지만 이름이 불필요하게 pleft 테이블의 각 행에 복제하는 방법주의 사항 :

당신은이 작업을 수행 할 수 있습니다. 이상적으로는 (id = 1, name = "Bob"), 태그를 모델링하는 하나의 테이블 (id = 6, value = "Skiing")과 관계를 포함하는 테이블 하나를 모델링하는 것이 좋습니다. 이렇게하면 예를 들어 Bob이 "Robert"로 이동하기로 결정한 경우 전체 태그 표를 디보핑 할 필요가 없으며 Bob이 관련된 한 행만 표시되도록 할 수 있습니다.

UPDATE

그래서 tags은 "1,4,6"을 들고 VARCHAR 필드입니다. 같은 논리가 적용되지만, 이제 다시 재결합하기 전에 필드를 분할해야합니다. "11"은 true를 반환하기 때문에 ("1"은 "11"에 모두 포함되어 있기 때문에) "1 in tags"와 같은 것을 사용할 수 없습니다. http://www.marcogoncalves.com/2011/03/mysql-split-column-string-into-rows/를 참조하십시오 또 다른 방법은 저장 프로 시저를 가지고하는 것입니다

SELECT pleft.name, GROUP_CONCAT(pright.tag) 
FROM pleft JOIN pright 
    ON (CONCAT(',',pleft.tags,',') LIKE CONCAT('%,',pright.id,',%')) 
GROUP BY pleft.name ORDER BY pleft.name; 

: (이 "무단 횡단"로 알려진 SQL 안티 패턴은, 예를 들어 https://groups.google.com/forum/?fromgroups=#!topic/django-users/5j4AmQE6nTk 참조).

CREATE TABLE pleft (id integer, name varchar(20), tags varchar(20)); 
INSERT INTO pleft VALUES (1, 'Bob', '1,4,6'), (2, 'Jill', '4,1'); 
SELECT pleft.name, GROUP_CONCAT(pright.tag) 
    FROM pleft JOIN pright 
     ON (CONCAT(',',pleft.tags,',') LIKE CONCAT('%,',pright.id,',%')) 
    GROUP BY pleft.name ORDER BY pleft.name; 
+------+-----------------------------+ 
| name | GROUP_CONCAT(pright.tag) | 
+------+-----------------------------+ 
| Bob | Sailing,Snowboarding,Skiing | 
| Jill | Sailing,Snowboarding  | 
+------+-----------------------------+ 
+0

머리를 올려 준 Isemi에게 감사드립니다. MySQL은 Jaywalkimg 반 패턴에 대해 그렇게 행동했습니다. 나중에 개발에 약간의 문제, 감사합니다! 그러나 LIKE로 해결 방법은 수십만 개의 행을 포함하는 테이블에 대해서는 느려질 것입니다. 더 빠른 방법이 없다면 제 3의 관계형 테이블을 생성 할 것입니다 – NaturalBornCamper

1

GROUP BY 이름 필드를 추가하면 태그로 모든 이름 목록을 선택할 수 있습니다.

SELECT `name`, GROUP_CONCAT(`right`.`tag`) AS tags 
FROM (`left`) 
LEFT OUTER JOIN `right` ON `right`.`id` IN(left.tags) 
GROUP BY `name` 
ORDER BY `name` ASC; 
+1

Nah는 작동하지 않습니다. 어쨌든 GROUP_BY를 사용하는 것은 없습니다. GROUP_CONCAT 쿼리는 어쨌든 하나의 행만 반환합니다. – NaturalBornCamper