ผลลัพธ์ที่ถูกต้องสำหรับแบบสอบถามนี้คืออะไร


20

ฉันเจอปริศนานี้ในความคิดเห็นที่นี่

CREATE TABLE r (b INT);

SELECT 1 FROM r HAVING 1=1;

SQL ServerและPostgreSQLส่งคืน 1 แถว

MySQLและOracleคืนค่าศูนย์แถว

อันไหนถูกต้อง? หรือทั้งสองอย่างนั้นถูกต้องเท่าเทียมกัน?


ปริศนาที่ดี ฉันคิดว่าถูกต้องคือการส่งคืน 1 แถว SQL-Server ขัดแย้งกับตัวเองเพราะSELECT COUNT(*) FROM r;ส่งคืน 1 แถว (พร้อม0) ในขณะที่SELECT COUNT(*) FROM r GROUP BY ();ไม่ส่งคืนแถว
ypercubeᵀᴹ

1
ต้องการมากขึ้น? SELECT 1 WHERE 1=0 HAVING 1=1;. SQL ServerและPostgreSQLยังคงส่งคืนแถวเดียว 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-row-no-dualและส่งคืน 0 แถว
ypercubeᵀᴹ

1
@SQLKiwi - สิ่งที่เกี่ยวกับข้อความนี้จากสเป็ค "ถ้า TE ไม่ประกอบด้วย a อยู่โดยทันที<group by clause>ก็“GROUP BY ()”จะเป็นนัย". แบบสอบถามทั้งสองไม่ควรส่งคืนผลลัพธ์เดียวกันหรือไม่
Martin Smith

1
แต่ไม่เห็นด้วยกับสิ่งเหล่านี้ (Oracle ประมวลผลการสืบค้นHAVINGต่างกัน): SQl-fiddle 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และแจ้งให้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>เป็นจริง

ลอจิก: เนื่องจากเงื่อนไขการค้นหาเป็นจริงเสมอผลคือRซึ่งเป็นผลลัพธ์ของกลุ่มโดยการแสดงออก


ต่อไปนี้เป็นข้อความที่ตัดตอนมาจากกฎทั่วไป 7.9 (คำจำกัดความของกลุ่มตาม CLAUSE)

1) ถ้าไม่<where clause>ได้ระบุไว้ให้Tเป็นผลของการก่อนหน้า<from clause>; มิฉะนั้นให้เป็นผลมาจากก่อนหน้านี้T<where clause>

2) กรณี:

ก) หากไม่มีคอลัมน์การจัดกลุ่มผลลัพธ์ของการ<group by clause>คือตารางที่จัดกลุ่มซึ่งประกอบด้วยTกลุ่มเดียว

ดังนั้นเราสามารถสรุปได้ว่า

FROM r GROUP BY ()

แสดงผลลัพธ์ในตารางที่จัดกลุ่มซึ่งประกอบด้วยหนึ่งกลุ่มโดยมีศูนย์แถว (เนื่องจาก R ว่างเปล่า)


ข้อความที่ตัดตอนมาจากกฎทั่วไปที่ 7.12 ซึ่งกำหนดข้อกำหนดการสืบค้น (หรือคำสั่ง SELECT):

1) กรณี:

a) หากTไม่ใช่ตารางที่จัดกลุ่มดังนั้น [... ]

b) ถ้าTเป็นตารางที่จัดกลุ่มแล้ว

กรณี:

i) หากTมีกลุ่ม 0 (ศูนย์) จากนั้นให้ TEMP เป็นตารางว่าง

ii) ถ้าTมีหนึ่งหรือมากกว่าหนึ่งกลุ่มแล้วแต่ละคน<value expression>จะถูกนำไปใช้กับแต่ละกลุ่มTให้ผลผลิตตารางTEMPของMแถวที่เป็นจำนวนของกลุ่มในM คอลัมน์ -th ของ TEMP มีค่าที่ได้มาจากการประเมินผลของ-th [ ... ]Tii<value expression>

2) กรณี:

ก) ในกรณีที่<set quantifier> DISTINCTไม่ได้ระบุไว้แล้วผลมาจากการที่เป็น<query specification>TEMP

ดังนั้นเนื่องจากตารางมีกลุ่มหนึ่งจึงต้องมีแถวผลลัพธ์หนึ่งแถว

ดังนั้น

SELECT 1 FROM r HAVING 1=1

ควรส่งคืนชุดผลลัพธ์ 1 แถว

QED


+1 ขอบคุณสำหรับปัญหาทั้งหมดที่เกิดขึ้น! ในฐานะที่เป็น @ypercube กล่าวว่า SQL Server ดูเหมือนจะขัดแย้งตัวเองที่นี่เป็นเลือก 1 จากกลุ่มตาม (); ส่งกลับศูนย์แถว แต่ข้อความที่คุณยกมาดูเหมือนชัดเจนในจุดนี้
Martin Smith

ฉันขอถามคุณหามาตรฐานได้จากที่ไหน ถ้าคุณบอกว่า 'บนชั้นวางหนังสือของฉันฉันจะผิดหวัง :)
Dezso

ในทางเทคนิคแล้วฉันใช้ Final Draft International Standard มากกว่ามาตรฐาน ตามกฎ ISO / IEC เท่านั้นอนุญาตให้มีการเปลี่ยนแปลงบรรณาธิการ (ไม่ใช่ด้านเทคนิค) ระหว่าง FDIS และมาตรฐานขั้นสุดท้าย มาตรฐานจะถูกแบ่งออกเป็นหลายส่วน ส่วนที่ 1 , ตอนที่ 2 , ส่วนที่ 4 ...
เควินแค็ ธ คาร์

Part 11และส่วน 14 ส่วนที่ 3,9,10 และ 13 ไม่ได้รับการอัปเดตในปี 2011 และใช้กับเวอร์ชันก่อนหน้า ไม่มีส่วนที่ 12 ในทำนองเดียวกันไม่มีส่วนที่ 5-8 ดูหน้า Wikipedia สำหรับ Sql: 2011หรือส่วนที่ 1 สำหรับคำอธิบายเกี่ยวกับสิ่งที่แต่ละส่วนมี
Kevin Cathcart

7

เมื่อมีHAVINGประโยคโดยไม่มีWHEREข้อ:

SELECT 1 FROM r HAVING 1=1;

... จากนั้นGROUP BY ()เป็นนัย ดังนั้นแบบสอบถามควรจะเท่ากับ:

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

... ซึ่งควรจัดกลุ่มแถวทั้งหมดของตารางเป็นหนึ่งกลุ่ม (แม้ว่าตารางจะไม่มีแถวเลย - ก็ยังคงเป็นกลุ่มหนึ่งของ 0 แถว) และส่งคืน 1 แถว HAVINGกับTrueสภาพที่ควรจะมีผลที่ทุกคนหลังจากนั้น


จากมุมที่แตกต่างกันแบบสอบถามจำนวนเท่าไหร่ที่ควรกลับมานี้

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

หนึ่งศูนย์หรือ "ศูนย์หรือหนึ่งขึ้นอยู่กับว่าตารางว่างเปล่าหรือไม่"?

ฉันคิดว่าแถวเดียวไม่ว่าจะมีกี่แถวrก็ตาม


ประเด็นสำคัญคือว่าจริงหรือไม่ที่ว่า "แม้ว่าตารางจะไม่มีแถวเลยก็ตามมันก็ยังคงเป็นกลุ่มหนึ่งของ 0 แถว" และมาตรฐานกลายเป็นที่ชัดเจนเกี่ยวกับเรื่องนี้: "หากไม่มีคอลัมน์การจัดกลุ่มดังนั้น ... คือตารางที่จัดกลุ่มซึ่งประกอบด้วย T เป็นกลุ่มเดียว" (และนั่นยังคงอยู่แม้ว่า T จะว่างเปล่า - ดังนั้นจึงมีกลุ่มแน่นอน) นอกจากนี้การมีประโยคระบุว่าเงื่อนไขจะถูกนำไปใช้กับแต่ละกลุ่ม (ในตัวอย่างจึงหนึ่งครั้ง) พวกเขาอาจกำหนดด้วยวิธีนี้เพื่อให้ SUM และ COUNT ส่งคืนหนึ่งแถวแม้จะว่างเปล่าของ T
เออร์วิน Smout

+1 (ก่อนหน้า!) แม้ว่าตรรกะของคุณจะเหมือนกับเควินฉันยอมรับคำตอบของเขาเพราะใบเสนอราคาจากสเป็ค ขอบคุณ!
Martin Smith

@MartinSmith ขอบคุณ ที่ฉันได้รับจากการเป็นคนขี้เกียจ :)
ypercubeᵀᴹ

@ypercube: +1 จากฉันด้วย ฉันตัดสินใจที่จะใช้เวลาพิเศษในการดึงจากสเป็คเพื่อพิสูจน์ว่าไม่มีคำพังพอนซ่อนอยู่ที่ไหนสักแห่งที่จะทำให้คำตอบของคุณผิด แต่เมื่อฉันทำอย่างนั้นฉันก็อาจโพสต์เป็นคำตอบเต็ม ดังนั้นฉันทำ
Kevin Cathcart

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;

ยังส่งคืนเพียงแถวเดียว แม้ว่าdocs SQLServerพูดว่า

เมื่อ GROUP BY ไม่ถูกใช้งาน HAVING จะทำตัวเหมือน WHERE clause

ไม่เป็นความจริงในกรณีนี้WHERE 1=1แทนที่จะHAVINGส่งกลับจำนวนแถวที่เหมาะสม ฉันว่ามันเป็นข้อผิดพลาดของเครื่องมือเพิ่มประสิทธิภาพ (หรือข้อผิดพลาดเอกสารอย่างน้อย) ... แผน SQLServer แสดง 'สแกนอย่างต่อเนื่อง' ในกรณีของHAVINGและ 'สแกนตาราง' สำหรับWHERE...

พฤติกรรมของ Oracle และ Mysql ดูสมเหตุสมผลและถูกต้องมากกว่าสำหรับฉัน ...


1
คุณพูดถูกว่า SQL Server ไม่ได้ดูที่ตาราง แผนการดำเนินการมีการสแกนอย่างต่อเนื่องและไม่ได้อ้างอิงตาราง ถ้าเป็นเพียง SQL Server ฉันจะใส่มันลงไปใน bug แต่มันไม่ใช่แค่ SQL Server ฉันสงสัยว่ามีความคลุมเครือของแท้อยู่ตรงนี้หรือไม่
Martin Smith

PostgreSQL แสดงผลลัพธ์เช่นเดียวกับ SQLServer และเท่าที่ฉันสามารถบอกได้จากผลลัพธ์ของexplain"ผลลัพธ์ (แถว = 1) ... " สำหรับการมีและ "Seq สแกน" สำหรับ "ที่" มันก็ไม่ได้มองเข้าไปในตาราง .. ฉันเดาว่ามันเกี่ยวข้องกับความจริงที่ว่า "FROM" นั้นไม่บังคับใช้ใน TSQL และ PostgreSQL ฉันรู้ว่า Mysql นั้นไม่จำเป็นต้องใช้เช่นกัน แต่เนื่องจากพวกเขาสนับสนุนdualพวกเขาจึงอาจแยกวิเคราะห์แบบสอบถามแตกต่างกันเล็กน้อย ฉันเห็นด้วยดูเหมือนว่าเป็นการเก็งกำไร แต่ฉันหวังว่ามันสมเหตุสมผล
a1ex07
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.