SQL Subquery mit Union / Except / Frage zur einfacheren Umsetzung (ggf. Exists?)

pizza4ever

Lt. Commander
Registriert
Apr. 2009
Beiträge
1.690
Hallo,

wenn man als einfaches Beispiel, aus einer Tabelle Bestellungen:

Tabelle Orders
TagDerBestellung, Artikelnummer, ... hundert weitere Spalten

die Daten von zwei Tagen haben will, die an genau nur einem Tag bestellt wurden, geht das nach meinem Wissen so:

(
select distinct Artikelnummer from Orders where TagDerBestellung = 'Tag 1'
except
select distinct Artikelnummer from Orders where TagDerBestellung = 'Tag 2'
)
union
(
select distinct Artikelnummer from Orders where TagDerBestellung = 'Tag 2'
except
select distinct Artikelnummer from Orders where TagDerBestellung = 'Tag 1'
)

wenn ich jetzt wieder die Ursprungsspalten brauche, musss ich noch ein Subselect auf die Ursprungstabelle machen. In meinem einfachen Beispiel geht das sogar noch, bei komplexeren Beispielen empfinde ich es aber als extrem komplex.

Gibts da eine einfachere Lösung?

Ich habe es schonmal mit Exists versucht, aber irgendwie hat das nicht so ganz funktioniert...

Verallgemeinert gesagt will ich aus einer Tabelle anhand verschiedener Spalten und einem Where Statement die Daten rausbekommen, nämlich hier die blaue Ergebnismenge:

1598161603880.png

(Quelle: https://dwgeek.com/snowflake-set-operators-union-except-minus-and-intersect.html/)
 
Zuletzt bearbeitet:
Versuchs mal mit

SQL:
SELECT *

  FROM Orders A

WHERE TagDerBestellung IN ('Tag1', 'Tag2')

AND NOT EXISTS(SELECT 1 FROM Orders B WHERE TagDerBestellung IN ('Tag1', 'Tag2') AND A.ArtikelNummer = B.ArtikelNummer AND A.TagDerBestellung <> B.TagDerBestellung)
 
Danke schonmla für das schenlle Feedback, ich probier gleich aus :-) . In meinem konkreten Beispiel wäre der Join auf die Tabelle:

AND A.ArtikelNummer = B.ArtikelNummer

umfangreich (vll 15.. 20 Spalten) - ist das dann noch best practice oder stimmt was mit dem Tabellendesign nicht?

Danke,

Alex
 
Deine Tabelle oben ist also nur ein Minimalbeispiel?
Naja, besser als ein doppelter except + union und dann wieder die attribute dranjoinen..
Aber ja, die Tabellenorganisation sollte ggf. überarbeitet werden.
Je nach SQL Standard / DBMS würde ich dann noch Temp Tabellen verwenden, um das ganze was schneller zu machen.
 
Ja, ist nur ein Minimalbeispiel und ich arbeite aktuell mit SQLite.

Im Prinzip ist mein Problem folgendes:

Ich speicher mir in eine SQLTabelle heruntergeladene Daten, größtenteils im Originalformat aber teilweise auf norminert (z.B. setze ich "Date" Felder auf den String wert "TODAY" um den Wert später vergleichen zu können da mich der konkrete Zeitstempel nicht interessiert.

Und danach muss ich eine Auswertung darauf machen, ob die Daten korrekt angelegt wurden, daher kommen die Abfragen.

Eine Alterantive wäre Tabelle aufzusplitten in einen Teil "vergleichbare Daten" und "originaldaten"
 
So, nun habe ich doch eine Frage.

Ich habe nun versucht das Statement auf das reale Beispiel zu übertragen und habe folgend(e) Problem(e)

1.) In meinem konkreten Beispiel liegen die Daten in zwei Tabellen, nicht in einer Tabelle, und es geht um die Frage ob es zu jedem Eintrag der Tabelle X einen Eintrag in der Tabelle Y gibt. Hierfür ausschlaggebend sind aktuell (beispielhaft) von 17 spalten 12.

Beispiel: Spalte A-C sind relevant, D nicht

Tabelle1:

ABCD
1​
1​
1​
1​
2​
2​
2​
2​
3​
3​
3​
3​
4​
4​
4​
4​

Tabelle2:



ABCD
1​
1​
1​
1​
2​
null
2​
2​
3​
3​
3​
null
4​
4​
4​
null

Im Ergebnis will ich sowas haben wie:



TabelleABCD
Tabelle1
2​
2​
2​
2​
Tabelle2
2​
null
2​
2​

... wobei man ehrlich gesagt sagen muss, dass ich nicht weiß ob in der Praxis Spalte D im Ergebnis wirklich vorkommen muss, also ehrlich gesagt würde:



TabelleABC
Tabelle1
2​
2​
2​
Tabelle2
2​
null
2​


mir auch reichen.

Gibts denn da eine Art "Best Practise" um das zu bekommen? Ich sehe folgende Möglichkeiten:

.. Aufbau einer Temp Table und mit deinem Statement und / oder union / Except
.. Umbau der Tabelle (Aufsplitten in "Vergleichbaren und nicht vergleichbaren Teil")
.. Es gibt irgeindeine schlaue SQL / SQLite native Lösung, die das kann.

Danke,

Alex
 
Die einfachen, Kontextlosen antworten:
1.:
pizza4ever schrieb:
wenn man als einfaches Beispiel, aus einer Tabelle Bestellungen[...]
die Daten von zwei Tagen haben will, die an genau nur einem Tag bestellt wurden[...]

SQL:
select Artikelnummer
from Orders
where TagDerBestellung in ('Tag 1', 'Tag 2')
group by Artikelnummer
having min(date(TagDerBestellung)) = max(date(TagDerBestellung))

2.:
pizza4ever schrieb:
TabelleABC
Tabelle1
2​
2​
2​
Tabelle2
2​
null
2​

Das ist ein left outer join/left join, nur dass du etwas mit deinen Spalten jonglieren musst, wenn du sie so haben willst, wie dargestellt.
(SQL geht einfach in die "Breite" und wird umständlich wenn von "Breite" in "Länge" oder von "Breite" zurück ins "Schmale" gegangen werden soll.)
SQL:
select *
from Tabelle1
left join Tabelle2 on (Tabelle1.ID = Tabelle2.ID)


Zu deinem Problem:
pizza4ever schrieb:
So, nun habe ich doch eine Frage.

Ich habe nun versucht das Statement auf das reale Beispiel zu übertragen und habe folgend(e) Problem(e)

1.) In meinem konkreten Beispiel liegen die Daten in zwei Tabellen, nicht in einer Tabelle, und es geht um die Frage ob es zu jedem Eintrag der Tabelle X einen Eintrag in der Tabelle Y gibt. Hierfür ausschlaggebend sind aktuell (beispielhaft) von 17 spalten 12.

Was ist in welcher Tabelle?
Hast du für jeden einzelnen Tag eine eigene Tabelle voller Orders?
Oder gehts jetzt um was anderes?

Das mal außen vor gelassen, was willst du denn genau von diesen zwei Tabellen wissen?
Wenn es das selbe ist wie vorher, dann nimm die antwort von 1. und ersetze Orders mit einem Union-Select-Statement:
SQL:
select Artikelnummer
from (select Artikelnummer, date(TagDerBestellung) TagDerBestellung
      from Tabelle1
     
      union
     
      select Artikelnummer, date(TagDerBestellung) TagDerBestellung
      from Tabelle2)
group by Artikelnummer
having min(TagDerBestellung) = max(TagDerBestellung)
 
Konkret für das Problem der im OP dargestellten Menge kann man sowas machen:

SQL:
(
SELECT ... FROM a
UNION 
SELECT ... FROM b
)
MINUS
(
SELECT ... FROM a
INTERSECT
SELECT ... FROM b

Allerdings sieht mir das mit dem beschriebenen Problem etwas spezifischer aus. Das schnuppert eher nach einem Fall für GROUP BY, eventuell einer Windowfunktion.

Wenn man mit DISTINCT anfangen muß, dann macht man in 9 von 10 Fällen was falsch.
 
Zurück
Oben