maexx77
Goto Top

Distinct Abfrage aber ohne Distinct

Hallo,

ich bekomme mit einer größeren Abfrage aus der Datenbank folgende Daten:

Artikel Maschine Material Datum
1----------A--------------------C----------1.1.2017
2----------A--------------------C----------1.2.2017
3----------B--------------------D----------1.1.2017
4----------B--------------------E----------1.1.2017
5----------A--------------------F----------1.1.2017

Nun möchte ich, dass die Ergebnismenge im Feld Material eindeutig ist.
Distinct kann ich nicht nehmen, da ich Artikel und Maschine aus Daten brauche und deshalb die Datensätze nicht herausgefiltert werden würden.
Select TOP 1 als Unterabfrage kann ich auch nicht nehmen, da ich wie gesagt alle Daten brauche und mehrere Unterabfragen zu heftig wären.

Im o.g. Fall will ich den 1. Datensatz rausschmeißen, damit das Material C nur einmal vorkommt. Diese Entscheidung soll auf Grund des Datum gefällt werden. Die Einträge bei Artikel 2 sind neuer.

Hat jemand eine Idee, wie ich das machen kann?
Ich stehe auf dem Schlauch.

Es würde evt. auch reichen, wenn die Bedingung mit dem Datum ignoriert wird. Ich brauche halt nur jedes Material einmal, mit irgendwelchen Infos unter Artikel und Maschine.

Gruß Mäxx

P.S. Das Ganze bitte nicht als gespeicherte Prozedur, wenn es geht.

Content-ID: 339420

Url: https://administrator.de/contentid/339420

Ausgedruckt am: 22.11.2024 um 09:11 Uhr

em-pie
Lösung em-pie 31.05.2017, aktualisiert am 03.06.2017 um 16:05:30 Uhr
Goto Top
Moin,

mal nur vom logischen Ansatz her:

wie wäre es mit einem Join auf die selbe Tabelle:

die zu joinende Tabelle hat eine Group by Clause:
SELECT
 A.Artikel
 , A.Material
 , A.Maschine
 , A.Datum
FROM
 Tbl as A
INNER JOIN
  (SELECT Material, Maschine, MAX(Datum)
  FROM Tbl
  GROUP BY Material, Maschine, Datum) as B on
  A.Maschine = B.Maschine AND A.Material=B.Material AND A.Datum = B.Datum

Der Code ist ungetestet, müsste aber ein brauchbares Ergebnis liefern, sofern ich jetzt nicht gerade einen Knoten im Kopf habe...

€dit: noch eine kurze Erklärung/ Anmerkung zum obigen Code. Ich gehe davon aus, dass wenn es eine folgende Kombination gäbe
1----------A--------------------C----------1.1.2017
2----------A--------------------C----------1.2.2017
3----------B--------------------D----------1.1.2017
4----------B--------------------E----------1.1.2017
5----------A--------------------E----------1.1.2017
6----------A--------------------F----------1.1.2017
du auch die Kombination B-E und A-E sehen möchtest!?
Wenn nicht, schmeiße aus dem Group by und dem dazugehörigen Select die Maschine raus, dann wird nur nach dem Material und dem Datum "gefiltert"

Gruß
em-pie
Maexx77
Maexx77 01.06.2017 um 07:38:09 Uhr
Goto Top
Das würde gehen. Dafür müsste ich aber die ursprüngliche Abfrage als Temp-Tabelle haben, was in einer Sicht nicht geht.
Bin aber auf die Funktion "first_value" gestoßen.
Damit geht es.
em-pie
em-pie 01.06.2017 aktualisiert um 21:40:31 Uhr
Goto Top
So geht es auch ^^

was mich allerdings noch irgendwie interessiert:
Dafür müsste ich aber die ursprüngliche Abfrage als Temp-Tabelle haben, was in einer Sicht nicht geht.

Wie meinst du das?

Ich habe bisher schon viel mit Views gearbeitet/ gebastelt/ vermurkst.
Eine View verhält sich mit reinen Select-Befehlen wie eine "normale" Tabelle. Soll heißen:
Eine View lässt sich (mit sich selbst) Joinen, als SubSelect verwenden oder als View innerhalb einer View verwenden, etc....

Was jedoch beim Erstellen von Views nicht geht (und eigentlich auch keinen Sinn ergibt), sind statements wie Order by.
z.B.
CREATE OR REPLACE VIEW "myView" AS  
SELECT Field1, Field2, Field3
FROM myTable
ORDER BY Field1
Das fürht (zumindest beim MS SQL-Server) immer zu abbrüchen/ Fehlermeldungen...

Gruß
em-pie
Maexx77
Maexx77 03.06.2017 um 14:45:05 Uhr
Goto Top
Das stimmt, da gebe ich dir vollkommen Recht. Das hatte ich auch versucht, aber irgendwie wollte es nicht funktionieren. Ich hatte meinen"Rohdaten" einen Namen gegeben. Dann hatte ich noch einen Namen für meine Group by Tabelle um an den Max Wert zu kommen. Diesen Namen wollte dann aber das SQL Studio nicht mehr zum joinen verwenden. Ich gebe aber auch zu, dass ich da nicht allzu viel Arbeit eingesteckt habe.

Die Lösung mit First_value kam schneller.
Biber
Biber 03.06.2017 um 14:47:59 Uhr
Goto Top
Moin Maexx77,

offen gestanden möchte ich diesen Beitrag nicht in diesem Zustand hier als "Gelöst" stehen lassen.

em-pie's Skizze würde - wenn sie denn berichtigt wäre und das tut, was es tun sollte - nicht das gewünschte Ergebnis bringen, wenn mehrere Artikel mit dem selben Material vorliegen.

Dein Kommentar "mit First_value klappt es" .... mag ja sein, aber auch da bringt doch "First_VALUE(Datum) OVER().."auch nur dasselbe wie ein Max(datum) OVER(..) ".

Vorteil wäre natürlich, dass du kein GROUP BY auf die Gesamt-Abfrage brauchst, also kein " SELECT ...., max(Datum) ...GROUP BY Artikel, Maschine, Material".

Kannst du bitte mal deine FIRST_VAULE() im ganzen Satz zeigen, damit es für nachfolgende Ratsuchende hilfreich wird?

Grüße
Biber
Maexx77
Maexx77 03.06.2017 um 14:51:05 Uhr
Goto Top
Ja, guter Einwand. Bin aber momentan unterwegs und am Handy ist es schwierig. Wird aber nachgeholt.
Maexx77
Maexx77 06.06.2017 aktualisiert um 10:03:58 Uhr
Goto Top
Hallo, hier die versprochene Lösung:

SELECT DISTINCT 
  FIRST_VALUE(ARTIKEL) OVER (PARTITION BY MATERIAL ORDER BY DATUM DESC) AS ARTIKEL,
  MASCHINE,
  MATERIAL
FROM T 
ORDER BY 
  MATERIAL
Biber
Biber 06.06.2017 aktualisiert um 13:03:14 Uhr
Goto Top
Moin Maexx77,

danke für deine Lösung.

Aber auch mit der habe ich ein bzw. zwei Verständnisprobleme.

Erstes Verständnisproblem:
em-pie hat doch in seinem konstruierten Beispiel eine der Sollbruchstellen aufgezeigt.

1----------A--------------------C----------1.1.2017
2----------A--------------------C----------1.2.2017
3----------B--------------------D----------1.1.2017
4----------B--------------------E----------1.1.2017
5----------A--------------------E----------1.1.2017
6----------A--------------------F----------1.1.2017

In diesen Beispiel würde doch das Material "E" auf zwei Maschinen (A und B) verwendet und für zwei unterschiedliche Artikel (4 und 5).

Dein SELECT würde daraus machen

2----------A--------------------C -> hier ist richtigerweise der Satz 1/Artikel 1ausgefiltert
3----------B--------------------D
4----------B--------------------E --> Hier würde als "Artikel" unvorhersagbar 4 oder 5 herauskommen als FIRST_VALUE()
4----------A--------------------E --> Hier würde als "Artikel" unvorhersagbar 4 oder 5 herauskommen als FIRST_VALUE()
6----------A--------------------F

Es ist somit mindestens eine ausgegebene Zuordnung Material-Maschine-Artikel falsch - im der Realität gibt/gab es die Kombination 4-B-E gar nicht.

Zweites Verständnisproblem: du musst zur Erreichung deines Ergebnisses noch ein DISTINCT über die Ergebnismenge machen.
Das ist nun auch nix anderes als ein GROUP BY über alle Felder und entsprechend teuer.

Wäre da nicht insgesamt ein einfaches GROUP BY in dieser Form
SELECT Artikel, Maschine, Material, max(Datum) as Datum
From t
GROUP BY Artikel, Maschine, Material
... günstiger?

Ergebnis in meiner Theorie wäre doch
2----------A--------------------C----------1.2.2017 -> hier ist richtigerweise der Satz 1/Artikel 1ausgefiltert
3----------B--------------------D----------1.1.2017
4----------B--------------------E----------1.1.2017
5----------A--------------------E----------1.1.2017
6----------A--------------------F----------1.1.2017


Wenn du dann zu einem dieser Ergebnissätze noch weitere Infos brauchst (Menge, Dauer, Stück, whatever), dann kannst du doch diesen Satz eindeutig über "Artikel, Maschine, Material, max(Datum)" identifizieren.

Grüße
Biber
Maexx77
Maexx77 06.06.2017 um 11:02:06 Uhr
Goto Top
Sicherlich wäre es auch machbar.
Der neue Ansatz mit first_value gefällt mir aber besser.
Biber
Biber 06.06.2017 um 13:02:07 Uhr
Goto Top
moin Maexx77,

okay, wenn das Ergebnis fachlich passt, dann ist es ja gut.

Grüße
Biber
Biber
Biber 06.06.2017 um 15:21:04 Uhr
Goto Top
... wobei allerdings jetzt unterm Strich die richtige Lösung für die Frage "DISTINCT-Abfrage ohne DISTINCT" ein "SELECT DISTINCT" ist.

Fiel mir grad so auf. face-wink

Aber so steht es geschrieben....

Grüße
Biber