SnowConvert AI - ANSI SQL - 하위 쿼리

설명

하위 쿼리는 다른 쿼리 내의 쿼리입니다. FROM 또는 WHERE의 하위 쿼리 절은 포함하는 쿼리에서 반환되는 데이터를 제한하거나 비교/평가하는 데 사용할 데이터를 제공하는 데 사용됩니다.(Snowflake 하위 쿼리 설명서).

하위 쿼리는 스칼라 하위 쿼리/스칼라가 아닌 하위 쿼리뿐만 아니라 상관 관계가 있는 쿼리/상관 관계가 없는 쿼리가 될 수 있습니다.

상관 관계가 있는 하위 쿼리는 외부 쿼리의 열을 참조합니다. Snowflake에서 상관 관계가 있는 하위 쿼리는 쿼리의 각 행에 대해 실행됩니다. 반면, 상관 관계가 없는 하위 쿼리는 외부 쿼리를 참조하지 않으며 전체 쿼리에 대해 한 번 실행됩니다.

스칼라 하위 쿼리는 단일 값을 결과로 반환하며, 그렇지 않은 경우 해당 하위 쿼리는 스칼라가 아닌 하위 쿼리입니다.

다음 패턴은 이러한 카테고리를 기반으로 합니다.

샘플 소스 패턴

설정 데이터

Teradata

CREATE TABLE tableA
(
    col1 INTEGER,
    col2 VARCHAR(20)
);

CREATE TABLE tableB
(
    col3 INTEGER,
    col4 VARCHAR(20)
);

INSERT INTO tableA VALUES (50, 'Hey');
INSERT INTO tableA VALUES (20, 'Example');

INSERT INTO tableB VALUES (50, 'Hey');
INSERT INTO tableB VALUES (20, 'Bye');
Copy

Snowflake

CREATE OR REPLACE TABLE tableA
(
    col1 INTEGER,
    col2 VARCHAR(20)
)
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "teradata",  "convertedOn": "12/02/2024",  "domain": "test" }}'
;

CREATE OR REPLACE TABLE tableB
(
    col3 INTEGER,
    col4 VARCHAR(20)
)
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "teradata",  "convertedOn": "12/02/2024",  "domain": "test" }}'
;

INSERT INTO tableA
VALUES (50, 'Hey');

INSERT INTO tableA
VALUES (20, 'Example');

INSERT INTO tableB
VALUES (50, 'Hey');

INSERT INTO tableB
VALUES (20, 'Bye');
Copy

상관 관계가 있는 스칼라 하위 쿼리

Snowflake는 컴파일 시 상관 관계가 있는 하위 쿼리를 평가하여 해당 하위 쿼리가 스칼라이며 따라서 단일 반환 값이 예상되는 컨텍스트에서 유효한지 확인합니다. 이 문제를 해결하기 위해 결과가 집계 함수가 아닌 경우 ANY_VALUE 집계 함수가 반환된 열에 추가됩니다. 이를 통해 컴파일러는 예상되는 단일 값 반환을 결정할 수 있습니다. 스칼라 하위 쿼리는 단일 값을 반환할 것으로 예상되므로 ANY_VALUE 함수는 결과를 변경하지 않으며, 원본 값을 있는 그대로 반환합니다.

Teradata

SELECT col2
FROM tableA
WHERE col1 = (SELECT col3 FROM tableB WHERE col2 = col4);
Copy

결과

+------+
| col2 |
+------+
| Hey  |
+------+
Copy

Snowflake

SELECT
    col2
FROM
    tableA
WHERE col1 =
             --** SSC-FDM-0002 - CORRELATED SUBQUERIES MAY HAVE SOME FUNCTIONAL DIFFERENCES. **
             (
                 SELECT
                     ANY_VALUE(col3) FROM
                     tableB
                 WHERE
                     RTRIM( col2) = RTRIM(col4));
Copy

결과

+------+
| col2 |
+------+
| Hey  |
+------+
Copy

상관 관계가 없는 스칼라 하위 쿼리

Snowflake는 상관 관계가 없는 스칼라 하위 쿼리를 완벽하게 지원합니다.

Teradata

SELECT col2, (SELECT AVG(col3) FROM tableB) AS avgTableB
FROM tableA
WHERE col1 = (SELECT MAX(col3) FROM tableB);
Copy

결과

+------+-----------+
| col2 | avgTableB |
+------+-----------+
| Hey  | 35        |
+------+-----------+
Copy

Snowflake

SELECT
    col2,
    (
                 SELECT
                     AVG(col3) FROM
                     tableB
    ) AS avgTableB
            FROM
    tableA
            WHERE col1 = (
                 SELECT
                     MAX(col3) FROM
                     tableB
    );
Copy

결과

+------+-----------+
| col2 | avgTableB |
+------+-----------+
| Hey  | 35.000000 |
+------+-----------+
Copy

스칼라가 아닌 하위 쿼리

하위 쿼리 연산자 내부에 지정된 스칼라가 아닌 하위 쿼리(ANY/ALL/IN/EXISTS)가 지원됩니다.

파생 테이블로 사용되는 스칼라가 아닌 하위 쿼리도 지원됩니다.

Teradata

SELECT col2
FROM tableA
WHERE col1 IN (SELECT col3 FROM tableB);

SELECT col2
FROM tableA
WHERE col1 >= ALL(SELECT col3 FROM tableB);

SELECT col2, myDerivedTable.col4
FROM tableA, (SELECT * FROM tableB) AS myDerivedTable
WHERE col1 = myDerivedTable.col3;
Copy

결과

+---------+
| col2    |
+---------+
| Example |
+---------+
| Hey     |
+---------+

+---------+
| col2    |
+---------+
| Hey     |
+---------+

+---------+------+
| col2    | col4 |
+---------+------+
| Example | Bye  |
+---------+------+
| Hey     | Hey  |
+---------+------+
Copy

Snowflake

SELECT
    col2
            FROM
    tableA
            WHERE col1 IN (
                 SELECT
                     col3 FROM
                     tableB
    );

                     SELECT
    col2
            FROM
    tableA
            WHERE col1 >= ALL(
                 SELECT
                     col3 FROM
                     tableB
    );
                    SELECT
    col2,
    myDerivedTable.col4
            FROM
    tableA, (
                 SELECT
                     * FROM
                     tableB
    ) AS myDerivedTable
            WHERE col1 = myDerivedTable.col3;
Copy

결과

+---------+
| col2    |
+---------+
| Example |
+---------+
| Hey     |
+---------+

+---------+
| col2    |
+---------+
| Hey     |
+---------+

+---------+------+
| col2    | col4 |
+---------+------+
| Example | Bye  |
+---------+------+
| Hey     | Hey  |
+---------+------+
Copy

Known Issues

**1. 상관 관계가 없는 스칼라가 아닌 FETCH를 먼저 사용하는 하위 쿼리

Oracle은 하위 쿼리에서 FETCH 절의 사용을 허용하지만, Snowflake는 하위 쿼리가 상관 관계가 없는 스칼라 하위 쿼리인 경우에만 이 절을 사용할 수 있도록 허용합니다. 그렇지 않은 경우에는 예외가 생성됩니다.

SnowConvert AI는 하위 쿼리에서 FETCH를 잘못 사용하는 경우 SSC-EWI-0108로 표시합니다.

Oracle:

-- Correlated scalar
SELECT col2
FROM tableA
WHERE col2 = (SELECT col4 FROM tableB WHERE col3 = col1 FETCH FIRST ROW ONLY);

-- Uncorrelated scalar
SELECT col2
FROM tableA
WHERE col2 = (SELECT col4 FROM tableB FETCH FIRST ROW ONLY);
Copy

Snowflake:

-- Correlated scalar
SELECT col2
FROM
    tableA
    WHERE col2 =
                 --** SSC-FDM-0002 - CORRELATED SUBQUERIES MAY HAVE SOME FUNCTIONAL DIFFERENCES. **
                 !!!RESOLVE EWI!!! /*** SSC-EWI-0108 - THE FOLLOWING SUBQUERY MATCHES AT LEAST ONE OF THE PATTERNS CONSIDERED INVALID AND MAY PRODUCE COMPILATION ERRORS ***/!!! (SELECT
                         ANY_VALUE( col4) FROM
                         tableB
                     WHERE col3 = col1
                     FETCH FIRST 1 ROW ONLY);
 
 -- Uncorrelated scalar
SELECT col2
FROM
    tableA
    WHERE col2 = (SELECT col4 FROM
                         tableB
                     FETCH FIRST 1 ROW ONLY); 
Copy