วิธีตรวจสอบว่าแบบสอบถามย่อยมีผลลัพธ์ที่แตกต่างกันหนึ่งรายการอย่างแน่นอนหรือไม่และค่าที่ระบุไว้รัดกุม?


10

ฉันพบว่าตัวเองเขียนข้อความต่อไปนี้:

select 'yes' 
where exists(select * from foo where val=1)
and not exists(select * from foo where val<>1);

และสงสัยว่ามีวิธีรัดกุมมากกว่านี้หรือไม่โดยไม่ต้องเสียสละความสามารถในการอ่านมากเกินไป

ฉันพบวิธีหนึ่งที่ฉันโพสต์เป็นคำตอบ แต่ฉันไม่พอใจกับมันโดยสิ้นเชิงและจะสนใจทางเลือกอื่น ๆ

ในกรณีนี้valจะไม่ซ้ำกันภายในfoo- ไม่มีการซ้ำซ้อน


ฉันเข้าใจถูกต้องหรือไม่ว่าคุณต้องการผลการสืบค้นย่อยหนึ่งแถวใช่หรือไม่
Erwin Brandstetter

แบบสอบถามย่อยใด
แจ็คบอกว่าลอง topanswers.xyz

คนที่คุณพูดถึงในชื่อ ฉันไม่แน่ใจว่าควรเป็นผลลัพธ์อย่างใดอย่างหนึ่งหลังจากหรือก่อน "ชัดเจน"
Erwin Brandstetter

อ่าใช่นั่นคือ :) ฉันค่อนข้างสับสนในการตอบคำถามย่อย - คำตอบของคุณมีความเฉพาะเจาะจงและมีความยืดหยุ่นมากขึ้นเช่นคุณสามารถใช้งานcount(distinct val)ได้แม้ในกรณีจริงของฉันมันไม่ต่างอะไรเลย
แจ็คบอกว่าลอง topanswers.xyz

คำตอบ:


8

กระชับเร็ว (โดยเฉพาะกับหลายแถว) สิ่งที่ฉันชอบเกี่ยวกับความสามารถในการอ่านและจะใช้งานร่วมกับ dupes ได้เช่นกัน:

SELECT count(*) = 1 AND min(val) = 1 FROM foo;

ส่งคืนTRUE/ FALSE.. หรือNULL- เฉพาะในกรณีที่มีหนึ่งแถวด้วยval IS NULLเพราะcount()ไม่เคยส่งคืนNULLหรือไม่มีแถว

ตัวอย่างที่สอง1นั้นเกิดขึ้นเหมือนกับในลำดับแรกเนื่องจากตัวอย่างของคุณ


แบบสอบถามในคำถามล้มเหลวด้วยNULLค่า พิจารณาตัวอย่างง่ายๆ:

CREATE TABLE foo (id int, val int);
INSERT INTO foo VALUES (1, 1),(2, NULL);

SELECT 'yes' 
WHERE      EXISTS(SELECT * FROM foo WHERE val =  1)
AND    NOT EXISTS(SELECT * FROM foo WHERE val <> 1);

IS DISTINCT FROMจะแก้ไขปัญหานี้ แต่ก็ยังอาจล้มเหลวหากมีรายการซ้ำvalซึ่งคุณได้ตัดสิทธิ์สำหรับกรณีนี้แล้ว


คำตอบของคุณใช้ได้ดี
ส่งคืน'yes'/ ไม่มีแถว

ฉันต้องการแบบฟอร์มที่สั้นกว่านี้ แต่ อย่าลืมว่า PostgreSQL (ซึ่งแตกต่างจากออราเคิล) มีที่เหมาะสมประเภทboolean

SELECT array_agg(val) = array[1] FROM foo;

ผลตอบแทนTRUE/ /FALSENULL


ยอดเยี่ยมขอบคุณผมรู้ว่าจะมีวิธีที่ดีกว่า :)
แจ็คบอกว่าลอง topanswers.xyz

5

รูปแบบของคำตอบของ @ Erwin ไม่มีCOUNT()ที่ทั้งหมดเพียงและMIN() MAX()อาจมีประสิทธิภาพมากขึ้นเล็กน้อยเมื่อใช้โต๊ะขนาดใหญ่และ (ไม่ใช่ในกรณีของคุณ) ซ้ำกันval:

SELECT MIN(val) = 1 AND MAX(val) = 1 FROM foo;

+1 มันจัดการโมฆะและซ้ำซ้อนแน่นอน (ถ้ามี)
แจ็คพูดว่าลอง topanswers.xyz

@ แจ็ค: ใช่ ตารางของคุณมีค่า Null หรือไม่? หรือคุณต้องการคำตอบสำหรับทั้งสองกรณี (มีหรือไม่มี)
ypercubeᵀᴹ

ไม่มีของฉันไม่ - ฉันสามารถใช้ได้ :)
แจ็คบอกลอง topanswers.xyz

จะเร็วขึ้นมากในตารางที่ใหญ่กว่าด้วยดัชนีที่ตรงกัน แต่ดำเนินการเหมือนกันในกรณีที่ไม่มีดัชนีเช่นเมื่อทดสอบผลลัพธ์ของแบบสอบถาม
Erwin Brandstetter


1

นี้เป็นหนึ่งในผลตอบแทนtrue, falseหรือผลที่ว่างเปล่า

 select j.val is null 
 from foo left join foo as j on j.val <> foo.val 
 where foo.val = 1 limit 1;

ได้อย่างรวดเร็วก่อนนี้ดูเหมือนจะไม่กลับfalseถ้ามีค่าในfooที่val<>1?
แจ็คบอกว่าลอง topanswers.xyz

@JackDouglas โอ้ขอโทษ ฉันเข้าใจงานผิดครั้งแรก แก้ไขแล้ว.
grayhemp

ใช้งานได้ - ยกเว้นด้วยNULLค่าซึ่งไม่ได้ถูกตัดออกในกรณีนี้
Erwin Brandstetter

@ErwinBrandstetter NULLสามารถใช้งานได้โดยใช้IS [NOT] DISTINCT FROMฉันคิดว่า
grayhemp

1
@grayhemp: ไม่ได้ในกรณีนี้ LEFT JOIN foo j ON j.val <> foo.valไม่สามารถตรวจสอบแถวj.val IS NULLที่เริ่มต้นด้วย หากคุณรวมไว้ในนั้นON j.val IS DISTINCT FROM foo.valคุณต้องตรวจสอบคอลัมน์อื่น ๆ ที่jกำหนดไว้NOT NULLเพื่อแจ้งให้ทั้งสองกรณีทราบกัน แต่ไม่มีการกำหนดคอลัมน์เพิ่มเติม
Erwin Brandstetter
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.