Bagaimana cara memeriksa apakah subquery memiliki satu hasil berbeda dan nilai yang ditentukan secara ringkas?


10

Saya menemukan diri saya menulis yang berikut:

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

dan bertanya-tanya apakah ada cara yang lebih ringkas tanpa mengorbankan terlalu banyak keterbacaan.

Saya menemukan satu cara yang saya posting sebagai jawaban tetapi saya tidak sepenuhnya senang dengan itu dan akan sangat tertarik dengan alternatif

Dalam hal valini unik di dalamnya foo- tidak ada duplikat


Apakah saya mengerti benar bahwa Anda ingin tepat satu baris dalam hasil subquery?
Erwin Brandstetter

Subquery yang mana?
Jack bilang coba topanswers.xyz

Yang Anda sebutkan dalam judul. Saya tidak yakin apakah itu harus menjadi satu hasil setelah atau sebelum "berbeda".
Erwin Brandstetter

Ah ya, yang itu :) Saya agak bingung merujuk ke sub-pertanyaan dalam jawaban saya - jawaban Anda jauh lebih spesifik dan fleksibel, misalnya Anda juga dapat menggunakan count(distinct val), meskipun dalam kasus dunia nyata saya tidak ada bedanya
Jack berkata coba topanswers.xyz

Jawaban:


8

Ringkas, cepat (terutama dengan banyak baris), favorit saya tentang keterbacaan dan akan bekerja dengan dupes juga:

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

Mengembalikan TRUE/ FALSE.. atau NULL- hanya dalam kasus tepat satu baris dengan val IS NULL, karena count()tidak pernah mengembalikan NULLatau tanpa baris.

Yang kedua 1dalam contoh kebetulan sama dengan yang pertama, karena contoh Anda.


Kueri dalam pertanyaan gagal dengan NULLnilai. Pertimbangkan demo sederhana:

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 FROMakan memperbaiki ini, tetapi masih bisa gagal dengan duplikat di val- yang telah Anda singkirkan untuk kasus ini.


Jawaban Anda bekerja dengan baik.
Kembali 'yes'/ tidak ada baris.

Saya lebih suka bentuk yang lebih pendek ini. Jangan lupa bahwa PostgreSQL (tidak seperti Oracle) memiliki booleantipe yang tepat .

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

Pengembalian TRUE/ FALSE/ NULL.


luar biasa, terima kasih, saya tahu akan ada cara yang lebih baik :)
Jack mengatakan coba topanswers.xyz

5

Variasi jawaban @ Erwin. Tidak COUNT()sama sekali, hanya MIN()dan MAX(). Mungkin sedikit lebih efisien dengan tabel besar dan (tidak dalam kasus Anda) duplikat val:

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

+1 terima kasih. Ini menangani nulls dan duplikat tentu saja berbeda (jika ada)
Jack mengatakan coba topanswers.xyz

@ Jack: Ya. Apakah meja Anda memiliki nol? Atau Anda ingin jawaban untuk kedua kasus (dengan dan tanpa)?
ypercubeᵀᴹ

tidak ada milik saya tidak - saya dapat menggunakan :)
Jack mengatakan coba topanswers.xyz

Akan jauh lebih cepat pada tabel yang lebih besar dengan indeks yang cocok, tetapi berkinerja identik dengan tidak adanya indeks seperti - seperti saat menguji hasil permintaan.
Erwin Brandstetter


1

Ini kembali true, falseatau hasil kosong:

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

pada pandangan pertama, ini sepertinya tidak kembali falsejika ada nilai di foomana val<>1?
Jack bilang coba topanswers.xyz

@ JackDouglas Oh, maaf. Saya mengerti tugas yang salah pertama kali. Tetap.
grayhemp

Bekerja - kecuali dengan NULLnilai yang belum dikesampingkan dalam kasus ini.
Erwin Brandstetter

@ ErwinBrandstetter NULLdapat dikerjakan dengan menggunakan IS [NOT] DISTINCT FROMkurasa.
grayhemp

1
@ grayhemp: Tidak dalam kasus ini. LEFT JOIN foo j ON j.val <> foo.valgagal mendeteksi baris dengan j.val IS NULLmulai. Jika Anda akan menyertakannya maka ON j.val IS DISTINCT FROM foo.valAnda perlu memeriksa kolom lain yang jditentukan NOT NULLuntuk membedakan kedua kasus tersebut. Tetapi tidak ada kolom tambahan yang didefinisikan.
Erwin Brandstetter
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.