Matty: MySQL - DINSTINCT und UNION

Ich habe ein etwas komische Problem in SQL zu lösen, und bisher ist mir dazu noch nix eingefallen. Ist auch nicht so einfach das ganze an einema
Anwendungsbeispiel zu erklären, deswegen mal etwas abstrakter:

Ich habe die Tabellen A B C D die alle das Feld datum enthalten. Tabellen B C D enthalten alle A.id als Fremdschlüssel.

jetzt möchte ich übergreifend über diese vier Tabellen alle Einträge nach dem Feld datum ( der jeweiligen Tabelle ) sortiert haben mit dem zusätzlichen Feld A.id (einmal direkt auf A und drei mal über ein JOIN auf A)

Das ganze funktioniert auch soweit mit:

  
(  
  SELECT DISTINCT `a_id`, `datum`  
  FROM A  
  
  UNION DISTINCT SELECT B.`a_id` as 'a_id', `datum`  
  FROM B  
  
  UNION DISTINCT SELECT C.`a_id` as 'a_id', `datum`  
  FROM C  
  
  UNION DISTINCT SELECT D.`a_id` as 'a_id', `datum`  
  FROM D  
)  
ORDER BY `datum` DESC  

... nur leider bekomme ich hier auch doppelte Einträge für a\_id und das will ich natürlich nicht... jede a\_id soll nur EINMAL zurückgeliefert werden. Dachte das dinstinct übernimmt das für mich... anscheinend aber nicht.

jemand eine Idee wie ich das in Pure-SQL lesen kann?

Danke euch :)

  1. Hallo

    Ich habe ein etwas komische Problem in SQL zu lösen, und bisher ist mir dazu noch nix eingefallen. Ist auch nicht so einfach das ganze an einema
    Anwendungsbeispiel zu erklären, deswegen mal etwas abstrakter:

    das ist keine gute Idee.

    jetzt möchte ich übergreifend über diese vier Tabellen alle Einträge nach dem Feld datum ( der jeweiligen Tabelle ) sortiert haben mit dem zusätzlichen Feld A.id

    ... nur leider bekomme ich hier auch doppelte Einträge für a\_id und das will ich natürlich nicht... jede a\_id soll nur EINMAL zurückgeliefert werden.

    Ich verstehe beim besten Willen nicht, welche Ergebnismenge Du haben möchtest.
    Bitte statte Deine Tabellen mit ein paar Beispieldatensätzen aus und gib dann
    das Ergebnis an, das aus diesen Daten resultieren soll - mit der Begründung,
    warum das Ergebnis so aussehen soll.

    jemand eine Idee wie ich das in Pure-SQL lesen kann?

    Diesen SQL-Dialekt kenne ich nicht. Deine (zum Verständnis eher hinderlichen)
    Backticks lassen mich auf MySQL schließen ...

    Freundliche Grüße

    Vinzenz

    1. Hallo

      Ich habe ein etwas komische Problem in SQL zu lösen, und bisher ist mir dazu noch nix eingefallen. Ist auch nicht so einfach das ganze an einema
      Anwendungsbeispiel zu erklären, deswegen mal etwas abstrakter:

      das ist keine gute Idee.

      Mhmm versteh ich zwar nicht aber okay.

      jetzt möchte ich übergreifend über diese vier Tabellen alle Einträge nach dem Feld datum ( der jeweiligen Tabelle ) sortiert haben mit dem zusätzlichen Feld A.id

      ... nur leider bekomme ich hier auch doppelte Einträge für a\_id und das will ich natürlich nicht... jede a\_id soll nur EINMAL zurückgeliefert werden.

      Ich verstehe beim besten Willen nicht, welche Ergebnismenge Du haben möchtest.
      Bitte statte Deine Tabellen mit ein paar Beispieldatensätzen aus und gib dann
      das Ergebnis an, das aus diesen Daten resultieren soll - mit der Begründung,
      warum das Ergebnis so aussehen soll.

      Mhmm naja, fand meine Erklärung eigentlich recht schlüssig.. aber hier dann nun mal mit Daten ..

      Tabelle A:
      id     |   datum
      1      |   100
      2      |   150
      3      |   200
      4      |   250
      5      |   300
      6      |   350

      Tabelle B:
      id     |   a_id    |  datum
      1      |    2      |  180
      2      |    2      |  150

      Tabelle C:
      id     |   a_id    |  datum
      1      |    1      |  90
      2      |    3      |  600

      Tabelle D:
      id     |   a_id    |  datum
      1      |    5      |  900
      2      |    2      |  150

      So mein SQL Query soll jetzt folgendes liefern ( mit ORDER BY datum DESC über die UNIONS .. id ist immer die a_id ..)

      id     |  datum
      5      |  900
      3      |  600
      6      |  350
      4      |  250
      2      |  180
      1      |  100

      Mein jetziges Query liefert jedoch folgendes (die a_id's kommen Mehrfach vor ...)

      id     |  datum
      5      |  900
      3      |  600
      6      |  350
      5      |  300   <- doppelt
      4      |  250
      3      |  200   <- doppelt
      2      |  180
      2      |  150   <- doppelt
      2      |  150   <- doppelt
      2      |  150   <- doppelt
      1      |  100
      1      |  90

      jemand eine Idee wie ich das in Pure-SQL lesen kann?

      Diesen SQL-Dialekt kenne ich nicht. Deine (zum Verständnis eher hinderlichen)
      Backticks lassen mich auf MySQL schließen ...

      Mein Beitrag hat einen Betreff... da steht das drin.. o_O
      mit "Pure-SQL" meine ich, dass ich keine Lösung will, die mir das ganze noch in der Anwendungslogik filtert, sondern es am besten wäre, meine Anforderung 'pure' in SQL zu lösen.

      Ist jetzt klar was ich will?

      Danke für die Hilfe und Gruß ,
      Matty

      1. Hallo

        das ist keine gute Idee.
        Mhmm versteh ich zwar nicht aber okay.
        Mhmm naja, fand meine Erklärung eigentlich recht schlüssig.. aber hier dann nun mal mit Daten ..

        Du vielleicht. Du weißt, was Du haben möchtest. Du kennst Deine Ausgangsdaten.
        Der geneigte Helfer jedoch nicht, wenn er nicht im Besitz einer funktionierenden
        Glaskugel ist.

        Tabelle A:
        id     |   datum
        1      |   100
        2      |   150
        3      |   200
        4      |   250
        5      |   300
        6      |   350

        Tabelle B:
        id     |   a_id    |  datum
        1      |    2      |  180
        2      |    2      |  150

        Tabelle C:
        id     |   a_id    |  datum
        1      |    1      |  90
        2      |    3      |  600

        Tabelle D:
        id     |   a_id    |  datum
        1      |    5      |  900
        2      |    2      |  150

        id     |  datum
        5      |  900
        3      |  600
        6      |  350
        4      |  250
        2      |  180
        1      |  100

        Mein jetziges Query liefert jedoch folgendes (die a_id's kommen Mehrfach vor ...)

        id     |  datum
        5      |  900
        3      |  600
        6      |  350
        5      |  300   <- doppelt
        4      |  250
        3      |  200   <- doppelt
        2      |  180
        2      |  150   <- doppelt
        2      |  150   <- doppelt
        2      |  150   <- doppelt
        1      |  100
        1      |  90

        aha, Du möchtest also nur die "neuesten" Werte zu jeder id haben. Ein ganz
        neuer Aspekt, der in Deinem Ausgangsposting nicht enthalten ist. Das kannst
        Du ganz einfach mit einer GROUP-BY-Klausel und der entsprechenden
        Aggregatsfunktion lösen.

        Freundliche Grüße

        Vinzenz

        1. aha, Du möchtest also nur die "neuesten" Werte zu jeder id haben. Ein ganz
          neuer Aspekt, der in Deinem Ausgangsposting nicht enthalten ist. Das kannst
          Du ganz einfach mit einer GROUP-BY-Klausel und der entsprechenden
          Aggregatsfunktion lösen.

          Nein du hast es nicht verstanden.

          Ich möchte nicht die neusten Werte zu jeder ID haben sondern ich möchte die aktuellsten Werte aus mehreren Tabellen haben, wobei die a_id nur atomar erscheinen soll. Ich glaube langsam, dass das nicht mit SQL zu lösen ist :(

          Hier mal das echte Statement ... mit GROUP BY klappt es _nicht_ (hatte ich schon probiert). Es erscheinen immernoch Duplikate der id

            
            
          SELECT DISTINCT `id` , 1, `datum`  
            FROM `ask`  
          UNION DISTINCT  
            SELECT `ask_id` AS 'id', 2, `datum`  
            FROM `answer`  
          UNION DISTINCT  
            SELECT AP.`ask_id` AS 'id', 3, `time` AS datum  
            FROM `poll_votes` AS PV  
            LEFT JOIN `ask_polls` AS AP  
              ON ( PV.`poll_id` = AP.`id` )  
          UNION DISTINCT  
            SELECT ANS.`ask_id` AS id, 4, AC.`datum`  
            FROM `answer_comments` AS AC  
            LEFT JOIN `answer` AS ANS  
              ON ( AC.`ans_id` = ANS.`id` )  
            WHERE ANS.id IS NOT NULL  
          UNION DISTINCT  
            SELECT `ask_id` AS id, 5, `datum`  
            FROM `ja_nein_ip_check`  
          UNION DISTINCT  
            SELECT `ask_id` AS id, 6, `datum`  
            FROM `ask_ip_check`  
            
          GROUP BY `id`  
          ORDER BY `datum` DESC  
          
          

          Ergebnis

          id  1  datum absteigend
          --------------------------------------
          185  3  2008-02-11 11:59:06 <-doppelt
          184  2  2008-02-11 11:56:00
          185  3  2008-02-11 11:46:56 <-doppelt
          181  6  2008-02-11 11:38:00
          177  6  2008-02-11 11:38:00
          182  6  2008-02-11 11:37:00
          185  3  2008-02-11 11:36:23 <-doppelt
          185  1  2008-02-11 11:34:00 <-doppelt
          176  6  2008-02-11 11:06:00

          Die zweite Spalte hier dient mir nur dazu, zu sehen aus welchem Union die Row kommt.

          Danke weiterhin im Voraus!

          Freundliche Grüße

          Vinzenz

          1. Hallo Matty,

            aha, Du möchtest also nur die "neuesten" Werte zu jeder id haben. Ein ganz
            neuer Aspekt, der in Deinem Ausgangsposting nicht enthalten ist. Das kannst
            Du ganz einfach mit einer GROUP-BY-Klausel und der entsprechenden
            Aggregatsfunktion lösen.

            Nein du hast es nicht verstanden.

            dann hast Du es falsch erklärt. Dein Beispiel zeigt _eindeutig_, dass Du nur
            an den jeweils größten Werten je id interessiert bist, gleichgültig in welcher Tabelle sie sich befinden.

            Ich möchte nicht die neusten Werte zu jeder ID haben sondern ich möchte die aktuellsten Werte aus mehreren Tabellen haben, wobei die a_id nur atomar erscheinen soll. Ich glaube langsam, dass das nicht mit SQL zu lösen ist :(

            wo ist das Problem? Bei _nur_ zwei Spalten läßt sich das problemlos mit
            GROUP BY und MAX() erledigen.

            Ergebnis

            id  1  datum absteigend

            185  3  2008-02-11 11:59:06 <-doppelt
            184  2  2008-02-11 11:56:00
            185  3  2008-02-11 11:46:56 <-doppelt
            181  6  2008-02-11 11:38:00
            177  6  2008-02-11 11:38:00
            182  6  2008-02-11 11:37:00
            185  3  2008-02-11 11:36:23 <-doppelt
            185  1  2008-02-11 11:34:00 <-doppelt
            176  6  2008-02-11 11:06:00

            Die zweite Spalte hier dient mir nur dazu, zu sehen aus welchem Union die Row kommt.

            die zweite Spalte macht den Ansatz mit GROUP-BY natürlich zunichte. Du darfst
            GROUP BY natürlich erst _auf das Ergebnis_ der UNION-Operation anwenden.

            Freundliche Grüße

            Vinzenz