Wie kann ich überprüfen, ob eine Unterabfrage genau ein bestimmtes Ergebnis und einen bestimmten Wert hat?


10

Ich habe Folgendes geschrieben:

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

und sich fragen, ob es einen prägnanteren Weg gibt, ohne zu viel Lesbarkeit zu beeinträchtigen.

Ich habe einen Weg gefunden, den ich als Antwort poste, bin aber nicht ganz zufrieden damit und würde mich sehr für Alternativen interessieren

In diesem Fall valist innerhalb eindeutig foo- es gibt keine Duplikate


Verstehe ich richtig, dass Sie genau eine Zeile im Ergebnis der Unterabfrage haben möchten?
Erwin Brandstetter


Die, die Sie im Titel erwähnen. Ich war mir nicht sicher, ob es ein Ergebnis nach oder vor "eindeutig" sein sollte.
Erwin Brandstetter

Ah ja, das hier :) Ich habe mich in meiner Antwort ziemlich verwirrend auf die Unterabfrage bezogen - Ihre ist weitaus spezifischer und flexibler, zB können Sie sie auch verwenden count(distinct val), obwohl es in meinem realen Fall keinen Unterschied macht
sagt Jack, versuchen Sie es topanswers.xyz

Antworten:


8

Prägnant, schnell (besonders bei vielen Zeilen), mein Favorit in Bezug auf Lesbarkeit und würde auch mit Dupes funktionieren:

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

Gibt TRUE/ FALSE.. oder NULL- nur bei genau einer Zeile mit zurück val IS NULL, da count()nie NULLoder keine Zeile zurückgegeben wird.

Die zweite 1im Beispiel ist aufgrund Ihres Beispiels zufällig dieselbe wie die erste.


Die Abfrage in der Frage schlägt mit NULLWerten fehl . Betrachten Sie die einfache Demo:

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 FROMwürde dies beheben, aber es könnte immer noch mit Duplikaten in fehlschlagen val- was Sie für diesen Fall ausgeschlossen haben.


Ihre Antwort funktioniert gut.
Rückgabe 'yes'/ keine Zeile.

Ich würde diese kürzere Form jedoch bevorzugen. Vergessen Sie nicht, dass PostgreSQL (im Gegensatz zu Oracle) einen geeigneten booleanTyp hat .

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

Rückgabe TRUE/ FALSE/ NULL.


ausgezeichnet, danke, ich wusste, dass es einen besseren Weg geben würde :)
Jack sagt, versuchen Sie es mit topanswers.xyz

5

Eine Variation von @ Erwins Antwort. Nein COUNT(), nur MIN()und MAX(). Bei großen Tischen und (in Ihrem Fall nicht) Duplikaten ist dies möglicherweise etwas effizienter val:

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

+1 danke. Es behandelt Nullen und Duplikate natürlich anders (falls vorhanden)
Jack sagt, versuchen Sie es mit topanswers.xyz

@ Jack: Ja. Hat Ihre Tabelle Nullen? Oder möchten Sie Antworten für beide Fälle (mit und ohne)?
Ypercubeᵀᴹ

Nein, meins nicht - ich kann es auch benutzen :)
Jack sagt, versuche topanswers.xyz

Wäre bei größeren Tabellen mit einem übereinstimmenden Index viel schneller, funktioniert jedoch ohne einen solchen Index identisch - wie beim Testen von Abfrageergebnissen.
Erwin Brandstetter


1

Diese kehrt man true, falseoder ein leeres Ergebnis:

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

Auf den ersten Blick scheint dies nicht zurückzukehren, falsewenn es Werte in foowo gibt val<>1?
Jack sagt, versuchen Sie es mit topanswers.xyz

@ JackDouglas Oh, sorry. Ich habe die Aufgabe beim ersten Mal falsch verstanden. Fest.
Grayhemp

Funktioniert - außer mit einem NULLWert, der in diesem Fall nicht ausgeschlossen wurde.
Erwin Brandstetter

@ErwinBrandstetter NULLkann mit IS [NOT] DISTINCT FROMmeiner Meinung nach ausgearbeitet werden .
Grayhemp

1
@grayhemp: In diesem Fall nicht. LEFT JOIN foo j ON j.val <> foo.valerkennt eine Zeile mit j.val IS NULLzunächst nicht. Wenn Sie es ON j.val IS DISTINCT FROM foo.valhinzufügen möchten, müssen Sie eine andere jdefinierte Spalte überprüfen NOT NULL, um die beiden Fälle voneinander zu unterscheiden. Es ist jedoch keine zusätzliche Spalte definiert.
Erwin Brandstetter
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.