이 쿼리에 대한 올바른 결과는 무엇입니까?


20

나는이 의견 에이 퍼즐 을 보았습니다.

CREATE TABLE r (b INT);

SELECT 1 FROM r HAVING 1=1;

SQL ServerPostgreSQL은 1 행을 반환합니다.

MySQLOracle은 0 행을 반환합니다.

어느 것이 맞습니까? 아니면 둘 다 똑같이 유효합니까?


좋은 퍼즐. 올바른 것은 1 행을 반환하는 것입니다. SQL-Server는 SELECT COUNT(*) FROM r;1 행 (with 0)을 SELECT COUNT(*) FROM r GROUP BY ();반환하지만 행은 반환하지 않기 때문에 모순됩니다 .
ypercubeᵀᴹ

1
더 원해? SELECT 1 WHERE 1=0 HAVING 1=1;. SQL ServerPostgreSQL은 여전히 하나의 행을 반환합니다. Oracle 은 FROM DUAL을 원하고 행을 리턴하지 않습니다. MySQL은 FROM DUAL 또는 컴파일 없이 컴파일하지 않습니다 .
Andriy M

1
@AndriyM 알 수없는 이유로 "dual"과 "HAVING"이 MySQL에서 제대로 작동하지 않습니다. (좋은 발견). 그러나 동등한 작동 : SELECT 1 AS t FROM (SELECT 1) tmp WHERE 1=0 HAVING 1=1; 1 행 없음 이중 및 0 행을 반환합니다.
ypercubeᵀᴹ

1
@SQLKiwi-스펙에서이 구절은 어떻습니까? "TE 즉시 포함되지 않은 경우 <group by clause>, 다음 “GROUP BY ()”암시입니다.". 두 쿼리 모두 동일한 결과를 반환해서는 안됩니까?
Martin Smith

1
그러나 이들에 동의 (오라클에 쿼리를 실행 HAVING다르게) : SQL-바이올린 2 : 다른 차종의 일을 HAVING
ypercubeᵀᴹ

답변:


17

표준에 따라 :

SELECT 1 FROM r HAVING 1=1

방법

SELECT 1 FROM r GROUP BY () HAVING 1=1

인용 ISO / IEC 9075-2 : 2011 7.10 구문 규칙 1 (HAVING 절 정의의 일부) :

하자 HC<having clause>. 하자 TE<table expression>즉시 포함 HC. 을 TE즉시 포함하지 않으면 <group by clause>" GROUP BY ()"가 암시 적입니다. 하자 T에 의해 정의 된 테이블의 기술자가 될 <group by clause> GBC즉시에 포함 TE하고 LET R의 결과 GBC.

그래야 꽤 분명합니다.


주장 : 1=1진정한 검색 조건입니다. 나는 이것을 인용하지 않을 것이다.


지금

SELECT 1 FROM r GROUP BY () HAVING 1=1

동등하다

SELECT 1 FROM r GROUP BY ()

인용 ISO / IEC 9075-2 : 2011 7.10 일반 규칙 1 :

<search condition>각 그룹에 대해 평가됩니다 R. 의 결과는 <having clause>R의 결과 <search condition>가 True 인 R 그룹의 그룹화 된 테이블입니다 .

논리 : 검색 조건이 항상 참이므로 결과는 R식에 의한 그룹의 결과 인입니다.


다음은 일반 규칙 7.9에서 발췌 한 것입니다 (GROUP BY CLAUSE 정의).

1) no <where clause>가 지정되면 T앞의 결과가된다 <from clause>. 그렇지 않으면 T앞의 결과를 보자 <where clause>.

2) 사례 :

a) 그룹화 열이 없으면 결과 는 유일한 그룹 <group by clause>으로 구성된 그룹화 된 테이블 T입니다.

따라서 우리는 결론을 내릴 수 있습니다

FROM r GROUP BY ()

행이 0 인 한 그룹으로 구성된 그룹화 된 테이블이됩니다 (R이 비어 있으므로).


쿼리 규정 (일명 SELECT 문)을 정의하는 7.12의 일반 규칙에서 발췌 한 내용 :

1) 사례 :

a) T그룹화 된 테이블이 아닌 경우 [...]

b) T그룹화 된 테이블 인 경우

케이스:

i) T그룹이 0 인 경우 TEMP를 빈 테이블로 둡니다.

ii) T하나 이상의 그룹이있는 경우 <value expression>각 그룹 은 행 그룹을 T생성하는 각 그룹에 적용됩니다 . 여기서 그룹의 수는입니다 . TEMP의 번째 열은의 평가에 의해 도출 된 값을 포함 번째를 . [...]TEMPMMTii<value expression>

2) 사례 :

a)를 <set quantifier> DISTINCT지정하지 않으면의 결과는 <query specification>입니다 TEMP.

따라서 테이블에는 하나의 그룹이 있으므로 하나의 결과 행이 있어야합니다.

그러므로

SELECT 1 FROM r HAVING 1=1

1 행 결과 집합을 반환해야합니다.

QED


+1 문제를 해결해 주셔서 감사합니다! @ypercube가 말했듯이 SQL Server는 여기서 SELECT 1 FROM r GROUP BY ()와 모순되는 것처럼 보입니다. 0 행을 반환하지만 인용 한 구절은이 점에서 분명합니다.
Martin Smith

어디에서 표준을 찾았습니까? '내 책장에'라고 말하면 실망 할 것입니다 :)
dezso

기술적으로 저는 표준 자체가 아니라 최종 초안 국제 표준을 사용했습니다. ISO / IEC 규칙에 따라 FDIS와 최종 표준 사이의 편집 (비 기술적) 변경 만 허용됩니다. 표준은 여러 부분으로 분리됩니다. 1 부 , 2 부 , 4 부 ...
케빈 캐스 카트

11 부 , 14 부 . 부품 3, 9, 10 및 13은 2011 년에 업데이트되지 않았으므로 이전 버전이 적용됩니다. 파트 12는 없습니다. 마찬가지로 파트 5-8도 없습니다. 각 부분에 포함 된 내용에 대한 설명은 Sql : 2011 Wikipedia 페이지 또는 Part 1 자체를 참조하십시오 .
케빈 캐스 카트

7

때이 HAVING없이 절, WHERE절은 :

SELECT 1 FROM r HAVING 1=1;

... 다음 GROUP BY ()은 암시 적입니다. 따라서 쿼리는 다음과 같아야합니다.

SELECT 1 FROM r GROUP BY () HAVING 1=1;

... 테이블의 모든 행을 하나의 그룹으로 그룹화해야합니다 (테이블에 행이 전혀 없어도 여전히 0 행의 한 그룹 임) .1 행을 반환하십시오. HAVINGTrue조건은 그 이후로 전혀 효과가 없습니다.


다른 각도에서, 이와 같은 쿼리는 몇 개의 행을 반환해야합니까?

SELECT COUNT(*), MAX(b) FROM r;

하나, 0 또는 "표가 비어 있는지 여부에 따라 0 또는 1"?

행 수에 관계없이 하나의 행을 생각 r합니다.


"핵심 문제는"테이블에 행이 전혀 없더라도 여전히 0 행의 한 그룹 "이라는 것이 사실인지 여부입니다. 그리고 표준은 이것에 대해 명백한 것으로 판명되었습니다. "그룹화 열이 없으면 ...이 유일한 그룹으로 T로 구성된 그룹화 된 테이블입니다." (T가 비어 있어도 유지됩니다. 따라서 실제로 그룹이 있습니다.) 또한 having 절은 조건이 각 그룹에 적용되도록 지정합니다 (이 예제에서는 한 번). 그들은 아마도 빈 T에 대해서도 SUM과 COUNT가 한 행을 반환하도록이 방법을 정의했을 것입니다.
Erwin Smout

+1 (이전!) 당신의 논리는 Kevin의 논리와 동일하지만 스펙의 인용문 때문에 그의 대답을 받아 들였습니다. 감사!
Martin Smith

@MartinSmith. Thnx. 내가 게으름에서 얻는 것 :)
ypercubeᵀᴹ

@ ypercube : 나도 +1. 나는 당신의 대답을 틀리게 만드는 어딘가에 숨겨진 족제비 단어가 없다는 것을 증명하기 위해 사양에서 벗어나기 위해 여분의 시간을 갖기로 결정했습니다. 그러나 일단 그렇게하면 전체 답변으로 게시 할 수 있습니다. 그래서 나는했다.
케빈 캐스 카트

3
@ ErwinSmout : 물론 아닙니다. 그러나 이것은 미국 저작권법에 따라 공정하게 사용됩니다. 교육 목적으로 저작물의 판매 능력에 무시할만한 영향을 미치면서, 저작물의 분석 (즉, 비판)의 맥락에서 인용 된 비교적 작은 부분.
Kevin Cathcart

3

내가 본 것에서 SQLServer와 PostgerSQL은 테이블을 전혀 보지 않아도됩니다.

CREATE TABLE r (b INT);
insert into r(b) values (1);
insert into r(b) values (2);
SELECT 1 FROM r HAVING 1=1;

또한 하나의 행만 반환합니다. 비록 SQLServer에 워드 프로세서가 말한다

GROUP BY를 사용하지 않으면 HAVING은 WHERE 절처럼 동작합니다.

이 경우에는 사실이 아닙니다. WHERE 1=1대신 HAVING적절한 수의 행 을 반환합니다. 나는 그것의 최적화 버그 (또는 적어도 문서 버그에서)라고 말하고 싶지만 ...의 경우 SQLServer에 계획 쇼 '콘스탄트 스캔' HAVING과 '테이블 스캔을' WHERE...

Oracle 및 Mysql 동작이 더 논리적이고 올바른 것 같습니다 ...


1
SQL Server가 테이블을 보지 않는 것이 맞습니다. 실행 계획은 일정한 스캔을 가지고 있으며 테이블을 참조하지도 않습니다. SQL Server 인 경우 버그에 버그를 넣었지만 SQL Server가 아니기 때문에 여기에 모호한 부분이 있는지 궁금합니다.
Martin Smith

PostgreSQL은 SQLServer와 동일한 결과를 보여 주며 explain"WHERE"에 대한 "Seq Scan"과 "Result (rows = 1) ..."의 출력에서 알 수 있는 한 테이블을 보지 않습니다. .. TSQL과 PostgreSQL에서 "FROM"이 필수가 아니라는 사실과 관련이있는 것 같습니다. 나는 Mysql도 그것을 필요로하지 않는다는 것을 알고 있지만 지원하기 때문에 dual쿼리를 약간 다르게 구문 분석 할 수 있습니다. 나는 그것이 추측처럼 들리지만, 그것이 의미가 있기를 바랍니다.
a1ex07
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.