Kết quả chính xác cho truy vấn này là gì?


20

Tôi đã xem qua câu đố này trong các ý kiến ​​ở đây

CREATE TABLE r (b INT);

SELECT 1 FROM r HAVING 1=1;

SQL ServerPostgreSQL trả về 1 hàng.

MySQLOracle trả về hàng không.

Cái nào đúng? Hoặc cả hai đều có giá trị như nhau?


Câu đố hay. Tôi nghĩ đúng là trả về 1 hàng. SQL-Server đang mâu thuẫn với chính nó bởi vì SELECT COUNT(*) FROM r;trả về 1 hàng (với 0), trong khi SELECT COUNT(*) FROM r GROUP BY ();trả về không có hàng.
ypercubeᵀᴹ

1
Muốn thêm? SELECT 1 WHERE 1=0 HAVING 1=1;. SQL ServerPostgreSQL vẫn trả về một hàng. Oracle muốn TỪ DUAL và không trả lại hàng. MySQL không biên dịch cả với TỪ DUAL cũng như không có nó .
Andriy M

1
@AndriyM Vì một số lý do không xác định "kép" và "HAVING" không chơi tốt trong MySQL. (Tìm kiếm tốt đẹp). Nhưng công việc tương đương: SELECT 1 AS t FROM (SELECT 1) tmp WHERE 1=0 HAVING 1=1; 1 hàng-không-kép và trả về 0 hàng.
ypercubeᵀᴹ

1
@QueryKiwi - Điều gì về đoạn văn này từ thông số kỹ thuật. "Nếu TE không ngay lập tức chứa a <group by clause>, thì đó “GROUP BY ()”là ẩn.". Không phải cả hai truy vấn đều trả về cùng một kết quả sao?
Martin Smith

1
Nhưng không đồng ý với những điều này (Oracle thực hiện các truy vấn HAVINGkhác nhau): SQl-fiddle 2: HAVING làm cho mọi thứ trở nên khác biệt
ypercubeᵀᴹ

Câu trả lời:


17

Theo tiêu chuẩn:

SELECT 1 FROM r HAVING 1=1

có nghĩa

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

Trích dẫn ISO / IEC 9075-2: 2011 7.10 Quy tắc cú pháp 1 (Một phần định nghĩa của mệnh đề HAVING):

Để cho HCđược <having clause>. Hãy TElà cái <table expression>mà ngay lập tức chứa HC. Nếu TEkhông ngay lập tức chứa a <group by clause>, thì thì GROUP BY ()CHUYỆN ẩn. Hãy Tlà mô tả của bảng được xác định bởi <group by clause> GBCngay lập tức có trong TERlà kết quả của GBC.

Ok rất nhiều điều đó là khá rõ ràng.


Khẳng định: 1=1là điều kiện tìm kiếm thực sự. Tôi sẽ không cung cấp trích dẫn cho việc này.


Hiện nay

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

tương đương với

SELECT 1 FROM r GROUP BY ()

Trích dẫn ISO / IEC 9075-2: 2011 7.10 Quy tắc chung 1:

Các <search condition>được đánh giá cho từng nhóm R. Kết quả của <having clause>một bảng được nhóm của các nhóm R mà kết quả của <search condition>nó là True.

Logic: Vì điều kiện tìm kiếm luôn luôn đúng, kết quả là R, là kết quả của nhóm theo biểu thức.


Sau đây là một đoạn trích từ Quy tắc chung của 7.9 (định nghĩa của NHÓM THEO YÊU CẦU)

1) Nếu không <where clause>được chỉ định, thì hãy Tlà kết quả của trước đó <from clause>; mặt khác, hãy Tlà kết quả của trước đó <where clause>.

2) Trường hợp:

a) Nếu không có các nhóm nhóm, thì kết quả của bảng <group by clause>là nhóm được bao gồm Tnhư là nhóm duy nhất của nó.

Do đó chúng ta có thể kết luận rằng

FROM r GROUP BY ()

kết quả trong một bảng được nhóm, bao gồm một nhóm, với các hàng bằng không (vì R trống).


Một đoạn trích từ Quy tắc chung của 7.12, định nghĩa Đặc tả truy vấn (còn gọi là câu lệnh CHỌN):

1) Trường hợp:

a) Nếu Tkhông phải là bảng được nhóm, thì [...]

b) Nếu Tlà một bảng được nhóm, thì

Trường hợp:

i) Nếu Tcó 0 (không) nhóm, thì hãy để TEMP là một bảng trống.

ii) Nếu Tcó một hoặc nhiều nhóm, thì mỗi nhóm <value expression>được áp dụng cho mỗi nhóm Tmang lại một bảng TEMPcác Mhàng, trong đó Msố lượng nhóm trong đó T. Các icột -thứ của TEMP chứa các giá trị thu được bằng cách đánh giá của i-thứ <value expression>. [...]

2) Trường hợp:

a) Nếu <set quantifier> DISTINCTkhông được chỉ định, thì kết quả của <query specification>TEMP.

Do đó, vì bảng có một nhóm, nên nó phải có một hàng kết quả.

Như vậy

SELECT 1 FROM r HAVING 1=1

sẽ trả về một tập kết quả 1 hàng.

QED


+1 Cảm ơn bạn đã đi đến tất cả những rắc rối đó! Như @ypercube nói rằng SQL Server dường như mâu thuẫn với chính nó ở đây là CHỌN 1 TỪ r GROUP BY (); trả về hàng 0 nhưng đoạn bạn trích dẫn có vẻ khá rõ ràng về điểm này.
Martin Smith

Tôi có thể hỏi bạn đã tìm thấy tiêu chuẩn ở đâu? Nếu bạn nói 'trên kệ sách của tôi' tôi sẽ thất vọng :)
dezso

Về mặt kỹ thuật, tôi đã sử dụng Tiêu chuẩn Quốc tế Dự thảo Cuối cùng, thay vì tiêu chuẩn. Mỗi quy tắc ISO / IEC chỉ được phép thay đổi biên tập (phi kỹ thuật) giữa FDIS và tiêu chuẩn cuối cùng. Các tiêu chuẩn được nhổ lên thành nhiều phần. Phần 1 , Phần 2 , Phần 4 ...
Kevin Cathcart

Phần 11Phần 14 . Phần 3,9,10 và 13 Không được cập nhật vào năm 2011, và do đó các phiên bản trước của chúng được áp dụng. Không có phần 12. Tương tự không có phần 5-8. Xem trang Wikipedia cho Sql: 2011 hoặc Phần 1 để biết giải thích về những gì mỗi phần chứa.
Kevin Cathcart

7

Khi có HAVINGmệnh đề, không có WHEREmệnh đề:

SELECT 1 FROM r HAVING 1=1;

... Sau đó GROUP BY ()là ngầm. Vì vậy, truy vấn phải tương đương với:

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

... sẽ nhóm tất cả các hàng của bảng thành một nhóm (ngay cả khi bảng không có hàng nào cả - nó vẫn là một nhóm 0 hàng) và trả về 1 hàng. Các HAVINGvới Trueđiều kiện nên không có hiệu lực ở tất cả sau đó.


Từ một góc độ khác, một truy vấn như thế này có bao nhiêu hàng?

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

Một, không hoặc "không hoặc một, tùy thuộc vào việc bảng có trống hay không"?

Tôi nghĩ một hàng, bất kể có bao nhiêu hàng r.


Vấn đề chính là liệu có thực sự đúng không "ngay cả khi bảng không có hàng nào cả, nó vẫn là một nhóm 0 hàng". Và tiêu chuẩn hóa ra rõ ràng về điều này: "Nếu không có các nhóm nhóm, thì ... là bảng được nhóm bao gồm T là nhóm duy nhất của nó". (và giữ ngay cả khi T trống - vì vậy thực sự có một nhóm.) Ngoài ra, mệnh đề có chỉ định rằng điều kiện được áp dụng cho mỗi nhóm (trong ví dụ như vậy một lần). Có lẽ họ đã định nghĩa nó theo cách này để làm cho SUM và COUNT trả về một hàng ngay cả đối với T trống.
Erwin Smout

+1 (trước đó!) Mặc dù logic của bạn giống như Kevin tôi đã chấp nhận câu trả lời của anh ấy vì các trích dẫn từ thông số kỹ thuật mặc dù. Cảm ơn!
Martin Smith

@MartinSmith. Thnx. Rằng tôi nhận được từ sự lười biếng :)
ypercubeᵀᴹ

@ypercube: +1 từ tôi nữa. Tôi quyết định dành thêm thời gian để lấy thông số kỹ thuật để chứng minh rằng không có từ chồn nào bị ẩn ở đâu đó sẽ khiến câu trả lời của bạn sai. Nhưng một khi tôi đã làm điều đó, tôi cũng có thể đăng nó như một câu trả lời đầy đủ. Tôi cũng vậy.
Kevin Cathcart

3
@ErwinSmout: Tất nhiên là không. Tuy nhiên, điều này rơi vào sử dụng hợp pháp theo luật bản quyền của Hoa Kỳ. Các phần tương đối nhỏ, được trích dẫn trong bối cảnh phân tích (nghĩa là phê bình) tác phẩm, cho mục đích giáo dục, với tác động không đáng kể đến khả năng bán tác phẩm.
Kevin Cathcart

3

Từ những gì tôi thấy, có vẻ như SQLServer và PostgerSQL hoàn toàn không bận tâm đến việc xem xét bảng:

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

cũng trả về chỉ một hàng. Mặc dù các tài liệu SQLServer nói

Khi GROUP BY không được sử dụng, HAVING hoạt động như một mệnh đề WHERE.

điều đó không đúng trong trường hợp này - WHERE 1=1thay vì HAVINGtrả về số lượng hàng thích hợp. Tôi muốn nói đó là lỗi tối ưu hóa (hoặc ít nhất là lỗi tài liệu) ... Gói SQLServer hiển thị 'Quét liên tục' trong trường hợp HAVINGvà 'quét bảng' cho WHERE...

Hành vi của Oracle và Mysql có vẻ hợp lý và đúng đắn hơn đối với tôi ...


1
Bạn nói đúng rằng SQL Server không nhìn vào bảng. Kế hoạch thực hiện chỉ quét liên tục và thậm chí không tham chiếu bảng. Nếu đó chỉ là SQL Server, tôi sẽ gặp phải một lỗi nhưng vì đó không chỉ là SQL Server, tôi tự hỏi liệu có sự mơ hồ thực sự nào ở đây không.
Martin Smith

PostgreSQL hiển thị các kết quả tương tự như SQLServer và theo như tôi có thể biết từ đầu ra của explain"Kết quả (hàng = 1) ..." khi có và "Seq Scan" cho "WHERE" thì nó cũng không nhìn vào bảng. .. Tôi đoán nó bằng cách nào đó liên quan đến thực tế là "TỪ" không bắt buộc trong TSQL và PostgreQuery. Tôi biết Mysql cũng không yêu cầu nó, nhưng vì họ hỗ trợ dual, nên có lẽ họ phân tích truy vấn hơi khác một chút. Tôi đồng ý, nó có vẻ như là một suy đoán, nhưng tôi hy vọng nó có ý nghĩa.
a1ex07
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.