2 voneinander abhängige Datenbankabfragen miteinander kombinieren



  • Hi,
    ich möchte aus einer MSSQL Datenbank Datensätze laden. Diese sieht folgendermaßen aus:

    ID | P | V 
    ---+---+------
    1  | 1 | NULL
    2  | 1 | 1
    3  | 2 | NULL 
    4  | 2 | 2
    5  | 3 | NULL
    

    Jetzt möchte ich bestimmte Vs laden, wobei jedes P genau einmal vorkommen soll:

    SELECT * FROM db WHERE V=1 OR V=2
    

    Da es von P=3 keine Werte zu diesen Vs gibt, möchte ich davon den "Defaultwert" mit V IS NULL haben.

    SELECT * FROM db WHERE V=1 OR V=2
    UNION
    SELECT * FROM db WHERE V IS NULL
    

    Jetzt hab ich zwar alle Ps drin, aber eben von P=1 und P=2 die einträge mit und ohne V.

    Gibt es eine Möglichkeit, in der zweiten Abfrage nur die Ps abzufragen, die in der ersten Abfrage nicht enthalten waren? Bzw umgekehrt die Ps auszuschließen, die in der ersten Abfrag bereits vorkamen?

    Es würde mir auch schon helfen, wenn ich das Resultset aus einer Abfrage als WHERE-Bedingung in einer zweiten Abfrage verwenden könnte.



  • Ich hab grad was gefunden:

    SELECT * FROM db WHERE V=2 OR V=3
    UNION
    SELECT * FROM db WHERE V IS NULL AND P NOT IN (SELECT P FROM db WHERE V=2 or V=3)
    

    Aber da der zweite Select befehl bis auf das Sternchen dem ersten entspricht, kann ich da nicht auch das Resultset vom ersten verwenden?



  • Ich weiß jetzt nicht, was es alles für Datenkonstellationen gibt, aber wie wäre es mit

    SELECT
        df.dw_id AS ID
      , df.dw_p AS P
      , df.dw_v AS V
    FROM defaultwerte AS df
    LEFT JOIN
    (
        SELECT 
          dw_id
        , dw_p
        , dw_v
        FROM defaultwerte
        WHERE dw_v IS NOT NULL
    ) sub ON sub.dw_p = df.dw_p
    WHERE sub.dw_id IS NULL
       OR df.dw_v IS NOT NULL
    

    oder noch etwas komprimierter

    SELECT
        df.dw_id AS ID
      , df.dw_p AS P
      , df.dw_v AS V
    FROM defaultwerte AS df
    LEFT JOIN defaultwerte AS sub ON sub.dw_p = df.dw_p
        AND sub.dw_v IS NOT NULL
    WHERE sub.dw_id IS NULL
       OR df.dw_v IS NOT NULL
    


  • Hm, ein Join würde die Daten ja horrizontal anhängen, ich benötige sie aber vertikal, darum union. Seh da im Moment keine Möglichkeit, das mit nem Join hinzubekommen...



  • Bevor ich jetzt alles erkläre, frag ich erstmal, was du als Ergebnis mit meiner Lösung herausbekommst
    und was noch falsch ist 😉 ... ich habe nur deine 5 Anfangsdatensätze



  • Das Ergebnis ist genau richtig. Das einzige, was ich ändern möchten würde ist, dass in dem Query nur noch ein SELECT steht. Also so wie:

    SELECT * FROM Test WHERE V=1 OR V=2
    UNION
    SELECT * FROM Test WHERE V IS NULL AND P NOT IN Test.P
    

    Nur noch Kosmetik...



  • Für was auch immer das gut sein soll.... aber man kann es sich auch umständlich machen 😃

    SELECT
        df.dw_id AS ID
      , df.dw_p AS P
      , df.dw_v AS V
    FROM defaultwerte AS df 
    WHERE df.dw_v IN (1,2)
    
    UNION
    
    SELECT
        df.dw_id AS ID
      , df.dw_p AS P
      , df.dw_v AS V
    FROM defaultwerte AS df 
    WHERE df.dw_v IS NULL
      AND df.dw_p NOT IN (
        SELECT
            df.dw_p AS P
        FROM defaultwerte AS df 
        WHERE df.dw_v IN (1,2)
      )
    

    Das mit dem direkten Zugriff über Test.P, wie du es schreibst, geht nicht. Da musst du auf ein Subselect zurückgreifen.

    PS: einen hab ich noch

    SELECT
        MAX(df.dw_id) AS ID
      , df.dw_p AS P
      , MAX(df.dw_v) AS V
    FROM defaultwerte AS df 
    GROUP BY df.dw_p
    

    EDIT: Wobei das mit der "MAX(df.dw_id) AS ID" eher nicht zu verwenden ist.



  • Sorry, hab mich falsch ausgedrückt: zwei Selects, auf jeder Seite vom Union eins...



  • Was soll das denn für Vorteile bringen gegenüber anderen Möglichkeiten, die einem die Datenbank zur Verfügung stellt 🙄



  • Auch die Datenbank ist nur ein Computer und muss (wie ich annehme) jedes Select verarbeiten. Wenn ich mir ein Select einfach sparen kann, ist doch prima. Funktionieren tuts so auch.
    Und nochmal zur verdeutlichung:
    Aktuell:

    SEELCT * FROM db WHERE ConditionA
    UNION
    SELECT * FROM db WHERE ConditionB AND P NOT IN (SELECT P FROM db WHERE ConditionA)
    

    Kosmetisch aufbereited:

    SEELCT * FROM db WHERE ConditionA
    UNION
    SELECT * FROM db WHERE ConditionB AND P NOT IN "Erster SELECT.P"
    


  • Auch die Datenbank ist nur ein Computer
    

    😃 und ich dachte, det wäre ne Software.

    Also deine kosmetisch aufbereitete Lösung funktioniert nun mal nicht, wie schon erwähnt. Ich glaube auch nicht, das UNION dafür erfunden wurde.
    Und bevor man eine Abfrage mehrfach in einer Query verwendet, kann man dies übersichtlicher gestalten und auf entsprechende JOINS zurückgreifen.

    Dein Threadtitel handelt schließlich von abhängigen Datenbankabfragen und da ist UNION sicher der falsche Ansatz.

    Aber vielleicht werde ich ja gleich von einem Datenbankguru belehrt.


Anmelden zum Antworten