[sql] SQL EXISTS 문은 어떻게 작동합니까?

SQL을 배우려고하는데 EXISTS 문을 이해하는 데 어려움을 겪고 있습니다. 나는 “존재한다”에 대한이 인용구를 보았는데 이해가되지 않는다.

exist 연산자를 사용하면 하위 쿼리가 0 개, 1 개 또는 여러 행을 반환 할 수 있으며 조건은 단순히 하위 쿼리가 행을 반환했는지 여부를 확인합니다. 하위 쿼리의 선택 절을 보면 단일 리터럴 (1)로 구성되어 있음을 알 수 있습니다. 포함 쿼리의 조건은 반환 된 행 수만 알면되므로 하위 쿼리가 반환 한 실제 데이터는 관련이 없습니다.

내가 이해하지 못하는 것은 외부 쿼리가 하위 쿼리가 확인하는 행을 어떻게 알 수 있다는 것입니다. 예를 들면 :

SELECT *
  FROM suppliers
 WHERE EXISTS (select *
                 from orders
                where suppliers.supplier_id = orders.supplier_id);

공급자와 주문 테이블의 ID가 일치하면 하위 쿼리가 true를 반환하고 공급자 테이블에서 일치하는 행의 모든 ​​열이 출력된다는 것을 이해합니다. 내가 얻지 못하는 것은 true 또는 false 만 반환되는 경우 하위 쿼리가 어떤 특정 행 (공급 업체 ID가 25 인 행이라고 말함)을 인쇄해야하는지 통신하는 방법입니다.

외부 쿼리와 하위 쿼리 사이에 관계가없는 것 같습니다.



답변

다음과 같이 생각하십시오.

의 ‘각’행의 Suppliers경우 Order테이블에 조건을 충족 하는 행이 ‘존재’ 하는지 확인합니다 Suppliers.supplier_id(이는 외부 쿼리 현재 ‘행’에서 가져옴) = Orders.supplier_id. 일치하는 첫 번째 행을 찾으면 바로 거기에서 중지하십시오 WHERE EXISTS.

외부 쿼리와 하위 쿼리 사이의 매직 링크는 Supplier_id평가 된 각 행에 대해 외부 쿼리에서 하위 쿼리로 전달되는 사실에 있습니다.

또는 다른 방법으로 말하자면, 하위 쿼리는 외부 쿼리의 각 테이블 행에 대해 실행됩니다.

하위 쿼리가 전체적으로 실행되고 ‘true / false’를 얻은 다음이 ‘true / false’조건을 외부 쿼리와 일치시키려는 것과는 다릅니다.


답변

외부 쿼리와 하위 쿼리 사이에 관계가없는 것 같습니다.

EXISTS 예제 내의 WHERE 절이 무엇을하고 있다고 생각하십니까? SUPPLIERS 참조가 EXISTS 절의 FROM 또는 JOIN 절에없는 경우 어떻게 결론을 내릴 수 있습니까?

EXISTS는 TRUE / FALSE에 대해 평가하고 기준의 첫 번째 일치에서 TRUE로 종료합니다. 이것이 IN. 또한 EXISTS의 SELECT 절이 무시된다는 점에 유의하십시오-IE :

SELECT s.*
  FROM SUPPLIERS s
 WHERE EXISTS (SELECT 1/0
                 FROM ORDERS o
                WHERE o.supplier_id = s.supplier_id)

… 0으로 나누기 오류가 발생해야하지만 그렇지 않습니다. WHERE 절은 EXISTS 절에서 가장 중요한 부분입니다.

또한 JOIN은 EXISTS에 대한 직접적인 대체가 아닙니다. 부모에 연결된 자식 레코드가 둘 이상인 경우 중복 부모 레코드가 있기 때문입니다.


답변

당신이 중 하나를 사용하여 동일한 결과를 생성 할 수 있습니다 JOIN, EXISTS, IN, 또는 INTERSECT:

SELECT s.supplier_id
FROM suppliers s
INNER JOIN (SELECT DISTINCT o.supplier_id FROM orders o) o
    ON o.supplier_id = s.supplier_id

SELECT s.supplier_id
FROM suppliers s
WHERE EXISTS (SELECT * FROM orders o WHERE o.supplier_id = s.supplier_id)

SELECT s.supplier_id
FROM suppliers s
WHERE s.supplier_id IN (SELECT o.supplier_id FROM orders o)

SELECT s.supplier_id
FROM suppliers s
INTERSECT
SELECT o.supplier_id
FROM orders o


답변

다음과 같은 where 절이있는 경우 :

WHERE id in (25,26,27) -- and so on

일부 행은 반환되고 일부는 반환되지 않는 이유를 쉽게 이해할 수 있습니다.

where 절이 다음과 같을 때 :

WHERE EXISTS (select * from orders where suppliers.supplier_id = orders.supplier_id);

그것은 단지 의미합니다 : 동일한 ID를 가진 orders 테이블에 기존 레코드가있는 행을 반환합니다.


답변

이것은 매우 좋은 질문 이므로이 주제에 대한 자세한 기사 를 블로그에 작성하기로 결정했습니다 .

데이터베이스 테이블 모델

데이터베이스에 일대 다 테이블 관계를 형성하는 다음 두 테이블이 있다고 가정 해 보겠습니다.

SQL EXISTS 테이블

student테이블은 부모이며,student_grade 이 학생 테이블의 ID를 기본 키 열을 참조하는 student_id 외래 키 열이 있기 때문에 자식 테이블입니다.

student table다음과 같은 두 개의 레코드를 포함 :

| id | first_name | last_name | admission_score |
|----|------------|-----------|-----------------|
| 1  | Alice      | Smith     | 8.95            |
| 2  | Bob        | Johnson   | 8.75            |

그리고 student_grade테이블에는 학생이받은 성적이 저장됩니다.

| id | class_name | grade | student_id |
|----|------------|-------|------------|
| 1  | Math       | 10    | 1          |
| 2  | Math       | 9.5   | 1          |
| 3  | Math       | 9.75  | 1          |
| 4  | Science    | 9.5   | 1          |
| 5  | Science    | 9     | 1          |
| 6  | Science    | 9.25  | 1          |
| 7  | Math       | 8.5   | 2          |
| 8  | Math       | 9.5   | 2          |
| 9  | Math       | 9     | 2          |
| 10 | Science    | 10    | 2          |
| 11 | Science    | 9.4   | 2          |

SQL 존재

수학 수업에서 10 점을받은 모든 학생을 모집한다고 가정 해 보겠습니다.

학생 식별자에만 관심이 있다면 다음과 같은 쿼리를 실행할 수 있습니다.

SELECT
    student_grade.student_id
FROM
    student_grade
WHERE
    student_grade.grade = 10 AND
    student_grade.class_name = 'Math'
ORDER BY
    student_grade.student_id

그러나 응용 프로그램은 student식별자뿐만 아니라의 전체 이름을 표시하는 데 관심이 있으므로student 테이블의 합니다.

student수학에서 점수가 10 인 레코드 를 필터링하기 위해 다음과 같이 EXISTS SQL 연산자를 사용할 수 있습니다.

SELECT
    id, first_name, last_name
FROM
    student
WHERE EXISTS (
    SELECT 1
    FROM
        student_grade
    WHERE
        student_grade.student_id = student.id AND
        student_grade.grade = 10 AND
        student_grade.class_name = 'Math'
)
ORDER BY id

위의 쿼리를 실행하면 Alice 행만 선택되었음을 알 수 있습니다.

| id | first_name | last_name |
|----|------------|-----------|
| 1  | Alice      | Smith     |

외부 쿼리는 student클라이언트에 반환하려는 행 열을 선택합니다 . 그러나 WHERE 절은 연결된 내부 하위 쿼리와 함께 EXISTS 연산자를 사용합니다.

EXISTS 연산자는 하위 쿼리가 하나 이상의 레코드를 반환하면 true를 반환하고 행을 선택하지 않으면 false를 반환합니다. 데이터베이스 엔진은 하위 쿼리를 완전히 실행할 필요가 없습니다. 단일 레코드가 일치하면 EXISTS 연산자가 true를 반환하고 연결된 다른 쿼리 행이 선택됩니다.

내부 하위 쿼리는 student_grade테이블 의 student_id 열 이 외부 학생 테이블의 id 열과 일치 하기 때문에 상관 관계 가 있습니다.


답변

EXISTS는 하위 쿼리가 적어도 하나의 행을 반환한다는 것을 의미합니다. 이 경우 외부 테이블의 supplier_id와 내부 테이블의 supplier_id를 확인하므로 상관 된 하위 쿼리입니다. 이 쿼리는 실제로 다음과 같이 말합니다.

모든 공급 업체 선택 각 공급 업체 ID에 대해이 공급 업체에 대한 주문이 있는지 확인 공급 업체가 주문 테이블에없는 경우 결과에서 공급 업체를 제거합니다. 주문 테이블에 해당 행이있는 모든 공급 업체 반환

이 경우 INNER JOIN을 사용하여 동일한 작업을 수행 할 수 있습니다.

SELECT suppliers.*
  FROM suppliers
 INNER
  JOIN orders
    ON suppliers.supplier_id = orders.supplier_id;

조랑말 댓글이 맞습니다. 해당 조인으로 그룹화하거나 필요한 데이터에 따라 구별을 선택해야합니다.


답변

설명하는 것은 상관 하위 쿼리가있는 소위 쿼리입니다 .

(일반적으로) 대신 조인을 사용하여 쿼리를 작성하여 피해야합니다.

SELECT suppliers.*
FROM suppliers
JOIN orders USING supplier_id
GROUP BY suppliers.supplier_id

그렇지 않으면 외부 쿼리의 각 행에 대해 하위 쿼리가 실행됩니다.