2011-11-04 3 views
0

이 문제에 대해 다음 3 가지 테이블을 고려하십시오.n : m 관계로 3 개의 테이블 조인, 일치하지 않는 행보기

Event 
id (pk) 
title 

Event_Category 
event_id (pk, fk) 
category_id (pk, fk) 

Category 
id (pk) 
description 

꽤 평범한 것 같아요. :) 각 이벤트는 0 개 이상의 범주로 나눌 수 있으며 총 4 개의 범주가 있습니다. 내 응용 프로그램에서 특정 이벤트의 범주를보고 편집하려고합니다. 그래픽으로 이벤트는 모든 카테고리와 함께 표시되며 이벤트가 카테고리에 속하는지 여부를 나타내는 체크 박스가 표시됩니다. 선택 사항을 변경하고 저장하면 중간 테이블 Event_Category가 수정됩니다. 하지만 먼저 : 특정 이벤트에 대해 이것을 선택하는 방법은 무엇입니까? 필자가 필요로하는 질의는 실제로 항상 4 개의 행을 반환 할 것이다.

다음은 id = 11 인 이벤트가 속하는 범주의 항목 만 리턴합니다. 외부 조인을 사용한 실험은 결과에 더 많은 행을주지 않았습니다.

SELECT e.id, c.omschrijving 
FROM Event e 
    INNER JOIN Event_Categorie ec ON e.id = ec.event_id 
    INNER JOIN Categorie c ON c.id = ec.categorie_id 
WHERE e.id = 11 

또는 쿼리의 범주 테이블부터 시작해야합니까? 희망 힌트 :) TIA, 클라스

업데이트 : 그래,하지만 여전히 대답을 찾지 못했습니다. 그러나이 테이블은 이벤트 설명을 보는 데만 사용되므로 쿼리에서 이벤트 테이블을 생략하여이 문제를 단순화했습니다.

SELECT * from Categorie c LEFT JOIN Event_Categorie ec ON c.id = ec.categorie_id WHERE ec.event_id = 11; 

단순화 된 2 테이블 쿼리는 조회 테이블과 링크 테이블 만 사용하지만 Categorie 테이블에서 총 4 개의 행 대신 2 개의 행만 반환합니다. 내 생각 엔 WHERE 절이 결합 후에 적용되므로 링크 테이블에 조인되지 않은 행은 제외됩니다. 내 응용 프로그램에서 하위 쿼리를 사용하여 문제를 해결했지만 여전히 최상의 솔루션이 무엇인지 알고 싶습니다.

+0

이런 종류의 질문은 이전에 여러 번 묻고 대답했습니다. StackOverflow를 게시하기 전에 검색해 보셨습니까? –

+0

예. 그래도 대답을 찾지 못했습니다. 그러나 나는이 문제를 단순화했다. – klausch

+0

원래 질문 아래에있는 업데이트를 참조하십시오 – klausch

답변

0

원하는 것은 모든 카테고리의 목록과 해당 카테고리가 이벤트 카테고리 목록에 있는지 여부에 대한 정보입니다.

SELECT 
    * 
FROM 
    Category 
    LEFT JOIN Event_Category ON category_id = id 
WHERE 
    event_id = 11 

및 EVENT_ID 열은 이벤트의 일부가 아닌 범주에 NULL이됩니다 :

그래서, 당신은 할 수 있습니다.

당신은 또한 당신이 이벤트가 NULL과 비교하는 대신이 범주가 있는지 확인하기 위해 사용하는 열 (아래라는 이름의 has_category) 만들 수 있습니다

:

SELECT 
    *, 
    event_id IS NOT NULL AS has_category 
FROM 
    Category 
    LEFT JOIN Event_Category ON category_id = id 
WHERE 
    event_id = 11 

편집 : 이것은 당신이 말하는 정확히 것을 편집 중. 나는 그것을 테스트하고 그것은 맞는 것 같습니다. 이 쿼리를 실행하고 있고 NULL이있는 행이 어떻게 든 무시되지는 않습니까?

+0

나쁜 레이아웃에 대한 변명, 여전히 어떻게 작동하는지 알아보기 :) – klausch

+0

이렇게 ... 두 쿼리 모두 2 행만 반환합니다. 필요에 따라 subselect가있는 행만 반환됩니다. – klausch

+0

어떤 플랫폼을 사용합니까? 이것은 일반적인 MySQL 설정에서 터미널에서 쿼리를 실행하는 것과 다릅니다. – abresas

0

쿼리

SELECT * FROM Categorie; 

반환 4 행 :

+----+--------------+-------------------------------------+--------------------------------------+ 
| id | omschrijving | afbeelding       | afbeelding_klein      | 
+----+--------------+-------------------------------------+--------------------------------------+ 
| 1 | Creatief  | images/categorieen/creatief420k.jpg | images/categorieen/creatief190k.jpg | 
| 2 | Sportief  | images/categorieen/sportief420k.jpg | images/categorieen/sportief190kr.jpg | 
| 4 | Culinair  | images/categorieen/culinair420k.jpg | images/categorieen/culinair190k.jpg | 
| 5 | Spirit  | images/categorieen/spirit420k.jpg | images/categorieen/spirit190k.jpg | 
+----+--------------+-------------------------------------+--------------------------------------+ 
4 rows in set (0.00 sec) 

하지만 : 쿼리

SELECT * 
FROM Categorie 
LEFT JOIN Event_Categorie ON categorie_id = id 
WHERE event_id = 11; 

반환 2 행 :

+----+--------------+-------------------------------------+-------------------------------------+----------+--------------+ 
| id | omschrijving | afbeelding       | afbeelding_klein     | event_id | categorie_id | 
+----+--------------+-------------------------------------+-------------------------------------+----------+--------------+ 
| 1 | Creatief  | images/categorieen/creatief420k.jpg | images/categorieen/creatief190k.jpg |  11 |   1 | 
| 4 | Culinair  | images/categorieen/culinair420k.jpg | images/categorieen/culinair190k.jpg |  11 |   4 | 
+----+--------------+-------------------------------------+-------------------------------------+----------+--------------+ 
2 rows in set (0.00 sec) 

그래서 여전히 하위 쿼리가 필요합니다 ... LEFT JOIN은 링크 테이블과 일치하는지 여부에 관계없이 CAtegorie 테이블의 모든 행을 표시하는 데는 효과적이지 않습니다.

+----+--------------+-------------------------------------+--------------------------------------+----------+--------------+ 
| id | omschrijving | afbeelding       | afbeelding_klein      | event_id | categorie_id | 
+----+--------------+-------------------------------------+--------------------------------------+----------+--------------+ 
| 1 | Creatief  | images/categorieen/creatief420k.jpg | images/categorieen/creatief190k.jpg |  11 |   1 | 
| 2 | Sportief  | images/categorieen/sportief420k.jpg | images/categorieen/sportief190kr.jpg |  NULL |   NULL | 
| 4 | Culinair  | images/categorieen/culinair420k.jpg | images/categorieen/culinair190k.jpg |  11 |   4 | 
| 5 | Spirit  | images/categorieen/spirit420k.jpg | images/categorieen/spirit190k.jpg |  NULL |   NULL | 
+----+--------------+-------------------------------------+--------------------------------------+----------+--------------+ 
4 rows in set (0.00 sec) 
+0

그리고 여전히 첫 번째 쿼리가 LEFT JOIN의 사용에도 불구하고 2 행만 반환하는 이유는 알지 못합니다. ( – klausch

0

문제는 당신이 이벤트 ID 기준으로 결과를 필터링 한 것입니다 :

SELECT * 
FROM Categorie c 
LEFT JOIN (SELECT * FROM Event_Categorie ec WHERE ec.event_id = 11) AS subselect ON subselect.categorie_id = c.id; 

결과 :

이 쿼리는, 그러나, 나는 그것이 무엇을 원하는 않습니다. 결과에서 볼 수 있듯이 두 가지 카테고리 (Sportief 및 Spirit)에는 이벤트가 없습니다. 올바른 SQL 문 (SQL Server 구문을 사용하여 일부 번역이 필요할 수 있음)은 다음과 같습니다.

SELECT * 
FROM Categorie 
LEFT JOIN Event_Categorie ON categorie_id = id 
WHERE (event_id IS NULL) OR (event_id = 11); 
+0

테스트 한 결과 2 행만 있습니다 ... 누락 된 행이 Event_Category 테이블과 일치하는 사람이 없으므로 이벤트 _id를 0으로 확인하면 트릭을 수행하지 않습니다. 여전히 유일하게 작동하는 쿼리는 subselect가있는 쿼리입니다. – klausch

+0

또한 링크 테이블의 event_id 필드는 기본 키의 일부이므로 NULL이 아닙니다! 실제로, WHERE 절을 절충 적으로 생략하면 결과에는 44 개의 행이 포함되지만 event_id = null에는 해당되지 않습니다. 그래서 이것은 분명히 원인이 아닙니다. – klausch

+0

왼쪽 범주 조인을 수행 할 때 주어진 범주에 대한 Event_Categorie 테이블에 항목이 없으면 event_id는 null이어야합니다.이것이 LEFT JOIN의 요점입니다. 첫 번째 테이블의 모든 레코드를 제공하고, 두 번째 테이블에 조인 조건과 일치하는 레코드가 있으면 두 번째 테이블에도 표시하고 그렇지 않으면 두 번째 테이블에 null을 표시합니다. 다른 모든 행에 null event_id가있는 마지막 결과 테이블에서이 정확한 작동을 볼 수 있습니다. –

0

마지막으로 올바른 쿼리를 찾았으므로 하위 선택이 필요하지 않습니다. 그러나 WHERE 절은 결합 후에 작동하므로 더 이상 결합의 일부가 아닙니다. 이 솔루션은 추가 조건으로 ON 절을 확장합니다. 일치하지 않는 카테고리에 대해 4 행 모두가 NULL로 반환됩니다!

SELECT * 
FROM Categorie 
LEFT JOIN Event_Categorie ON categorie_id = id AND event_id = 11; 

따라서 ON 절에 여분의 조건을 넣는 것이 WHERE 절에서 같은 조건으로 행을 필터링하는 것과는 다른 효과가 있습니다!

관련 문제