SQL: Duplikate vermeiden

Diskutiere das Thema SQL: Duplikate vermeiden im Forum Web-Programmierung

  1. Saugkraft

    Saugkraft Thread Starter Super Moderator

    Beiträge:
    9.122
    Medien:
    1
    Zustimmungen:
    3.082
    Mitglied seit:
    20.02.2005
    Hallo SQL Experten,

    ich sitze grad an einem relativ kniffligen Problem und ich weiß nicht, ob es dazu eine reine SQL Lösung gibt. Ich habe eine Abfrage bei der datensatz_id, status1, status2 und datum abgefragt werden sollen.

    datensatz_id und status1 kommen aus Tabelle 1.
    datensatz_id ist Fremdschlüssel in Tabelle 2. Aus Tabelle 2 lese ich status2 und datum aus.

    status1 kann true sein, status2 kann true sein oder alle beide.

    In Tabelle 2 sind jeder datensatz_id aus Tabelle 1 mehrere Datumswerte zugeordnet.

    Ich will abfragen, an welchen Tagen (Datum) status1, status2 oder alle beide true sind. Dabei soll nach Datumswerten sortiert werden.

    Soweit so gut. Problem: Ich will jede datensatz_id nur einmal aufgeführt bekommen.

    Mit
    Code:
    SELECT tabelle1.datensatz_id, tabelle1.status1, tabelle2.status2, tabelle2.datum INNER JOIN tabelle1 ON tabelle1.datensatz_id = tabelle2.datensatz_id WHERE tabelle1.status1 = true OR tabelle2.status2 = true GROUP BY tabelle1.datensatz_id, tabelle1.status1, tabelle2.status2, tabelle2.datum ORDER BY MIN(tabelle2.datum)
    spuckt er mir die Datensätze aus, führt aber ggf. die datensatz_id doppelt auf. Nämlich dort wo ein status true ist und mehrere Datumseinträge zu einer datensatz_id existieren.

    Zum Beispiel so:
    Code:
    datensatz_id status1 status2 datum
           2           true     false   1.1.2008
           2           true     false   2.1.2008
           3           true     true    5.1.2008
           3           true     true    7.1.2008
           2           false    true    8.1.2008
           1           true     true    9.1.2008
    
    Was ich brauche ist das jeweils erste Datum bei dem eine datensatz_id auftaucht. Bei 2 z.B. der 1.1.2008. Danach ist die datensatz_id "verbraucht" und darf nicht wieder auftauchen. Das Ergebnis sollte also so aussehen:
    Code:
    datensatz_id status1 status2 datum
           2           true     false   1.1.2008
           3           true     true    5.1.2008
           1           true     true    9.1.2008
    
    Warum das so sein muss? Da hängen natürlich noch ein paar andere Daten aus anderen Tabellen dran. Wenn ich daraus eine Webseite generiere, kommen die Daten geclustert zum Einsatz und zu jeder id werden die Datumswerte nochmal gesondert abgefragt (plus ein paar Zusatzinfos):

    Beginn: 1.1.2008
    id: 2
    Termine: 1.1.2008, 2.1.2008, 8.1.2008

    Entscheidend für die Sortierung ist aber der erste Termin. Wenn die id mehrfach (irgendwo weiter hinten in der Liste nochmal) auftaucht, haut er mir dazu natürlich nochmal die 4 Termine raus. Das will ich natürlich nicht.

    Ich kann an der Datenbank Struktur nichts ändern. Dazu hängt zuviel hinten dran. Die Frage ist also: Gibt es dafür eine reine SQL Lösung oder muss ich in ASP, PHP, etc. was programmieren um bereits abgearbeitete ids zu überspringen?

    Ich hoffe, ihr könnt mir helfen.
     
  2. somunium

    somunium Mitglied

    Beiträge:
    326
    Zustimmungen:
    35
    Mitglied seit:
    16.01.2008
    Hm... Das einzige, was mir jetzt einfällt, währe das über mehrere einzelne Querys zu machen.

    Für jede datensatz_id einen eigenen, der sich dann mit LIMIT und ORDER jeweils den ersten Satz holt.

    Wird aber bei vielen Sätzen recht unperfomant...

    Ansonsten, schau Dir mal den GROUP-Befehl an. Den hab ich jetzt nicht so gut drauf, aber mein Instinkt sagt mir, dass, wenn es möglich ist, es damit möglich ist :D

    (Männlicher Instinkt, keine Weibliche Intuition :D)
     
  3. timbajr

    timbajr Mitglied

    Beiträge:
    579
    Zustimmungen:
    26
    Mitglied seit:
    22.04.2005
    Mit GROUP BY und FIRST. Schau dir mal group by und die sog. Aggregatfunktionen an.
     
  4. frikih

    frikih Mitglied

    Beiträge:
    24
    Zustimmungen:
    3
    Mitglied seit:
    10.02.2007
    das sollte per SQL ohne Probleme möglich sein, poste doch mal bitte die genau Struktur der Tabellen mit Primärschlüsseln etc... das macht es einfacher.
     
  5. Internetlady

    Internetlady Mitglied

    Beiträge:
    2.023
    Zustimmungen:
    7
    Mitglied seit:
    06.03.2005
    Hast du es schon mal mit DISTINCT und einem LEFT JOIN Probiert? *

    SELECT DISTINCT tabelle1.datensatz_id…
    FROM (tabelle1 LEFT JOIN tabelle2
    ON tabelle1.datensatz_id = tabelle2.datensatz_id)
    WHERE…. (Datumsanfrage muss hier rein u.a.)



    *ggf. nur DB2 Syntax ...
    aber müsste es für alle Datenbanken ja analoges zu geben
     
  6. wegus

    wegus Mitglied

    Beiträge:
    16.002
    Zustimmungen:
    2.547
    Mitglied seit:
    13.09.2004
    auf die Schnelle fiele mir ein:

    GROUP BY datensatz_id

    und

    ORDER BY tabell2.datum

    das sollte ggf helfen die Zeilen auf eine ( die älteste) zu reduzieren. Da Du ja im Prinzip nur die Datensätze ausschließt bei denen status1 und status2 false sind, bekommst Du auch mit INNER JOINS keine besseren Daten.

    Ggf. kann man die Zeilen auch erstmal alle so in eine temporäre Tabelle schreiben und dort mit einem 2ten Statement nur die jeweils ältesten Einträge je ID herauslesen. Sind zwei Schritte aber ggf. etwas übersichtlicher!
     
  7. wegus

    wegus Mitglied

    Beiträge:
    16.002
    Zustimmungen:
    2.547
    Mitglied seit:
    13.09.2004
    an DISTINCT hab ich auch gedacht, bezieht sich denn DISTINCT nur auf die eine Spalte oder ist DISTINCT je Resultset/Tupel gemeint? Im letzteren Fall dürfte das ja kaum helfen.
     
  8. dms

    dms

    Sowohl, als auch, wenn ich mich nicht irre.

    SELECT DISTINCT spalte FROM tabelle

    vs.

    SELECT DISTINCT(spalte) FROM tabelle
     
  9. Saugkraft

    Saugkraft Thread Starter Super Moderator

    Beiträge:
    9.122
    Medien:
    1
    Zustimmungen:
    3.082
    Mitglied seit:
    20.02.2005
    FIRST wird vom MS SQL Server 2000 nicht unterstützt. :hum: Wird Zeit, dass ich mal auf 2008 update.

    DISTINCT datensatz_id klappt auch nicht. Weder mit LEFT JOIN noch ohne. Ich bin mir nicht sicher, aber ich vermute, dass sich DISCTINCT auf das Resultset bezieht.

    Das Problem ist ja, dass ich selbst wenn ich die datensatz_id gruppiere und per MIN DISTINCT die Datumswerte eingrenze, zwei oder mehr Daten erhalte, bei denen die Kriterien erfüllt sind. Dadurch unterscheiden sich die Ergebnissätze und für jedes unterschiedliche Datum wird mir die datensatz_id mit ausgespuckt.

    frikih: Die Struktur sieht so aus..
    Tabelle 1: datensatz_id (Primärschlüssel, ID), status1
    Tabelle 2: tbl2_id, datensatz_id (Fremdschlüssel von Tabelle 1), status2, datum

    Sind zwar noch mehr Felder drin aber die kommen nicht zum Einsatz und bilden auch keine Verknüpfung zwischen den Tabellen.

    Das mit der temporäten Tabelle hab ich mir auch schon überlegt, müsste allerdings erstmal rausfinden ob das mit dem SQL 2000 geht. Vielleicht kann ich ja auch eine Abfrage auf eine Abfrage legen.

    Alternativ böte sich noch ASP.NET an, da kann man Abfragen auf das Ergebnis anwenden weil die Daten nicht als Recordset sondern in einer Tabellenstruktur vorliegen. Der Nachteil ist, dass die Datensatznavigation da nicht per Zeiger funktioniert und für mein kleines Hirn offensichtlich zu kompliziert ist.
     
  10. wegus

    wegus Mitglied

    Beiträge:
    16.002
    Zustimmungen:
    2.547
    Mitglied seit:
    13.09.2004
    [QUOTE="Saugkraft]Das mit der temporäten Tabelle hab ich mir auch schon überlegt, müsste allerdings erstmal rausfinden ob das mit dem SQL 2000 geht. Vielleicht kann ich ja auch eine Abfrage auf eine Abfrage legen.[/QUOTE]

    das geht in jedem Fall! Nutze das selbst hier. Auf die Schnelle aus dem Kopf ohne Gewähr: temp. Tabellen beginnen mit einer # glaub ich!
    EDIT: stimmte :) #tabelle ist lokale temporäre Tabelle ( nur für Deinen einen Connect) ##tabelle ist eine globale temporäre Tabelle. Mehr gibt es im Query Analyzer unter Hilfe zu Transact SQL wenn Du nach temporär suchst!

    hast Du das mit GROUP BY probiert? Immerhin ist das das Mittel der Wahl da auf eine Zeile herunterzubrechen.
     
Die Seite wird geladen...

MacUser.de weiterempfehlen

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies. Akzeptieren Weitere Informationen...