Michael Huhn: Komplexe MsSQL-Abfrage in einer stored procedure

Folgendes Problem: ich habe aus einem Select ein RecordSet mit IDs. Jetzt will ich aus einem anderen Table, der im JOIN des ersten Selects nicht benutzt wurde, alle Einträge zurückgeben, der Table soll jedoch ein zusätzliches Feld blnPossible haben, das auf true gesetzt wird, wenn die ID des Eintrags in dem ersten SELECT vorkam.

also:
SELECT irgendwas FROM Table1 JOIN Table2

gibt 10 und 11 zurück.

Table3 enthält Einträge mit den IDs 10,11 und 12. Jetzt will ich alle Einträge aus Table3 zurückgeben, allerdings soll eine zusätzliche Column blnPossible bei 10 und 11 auf true gesetzt sein, bei 12 auf false. Wie mache ich das?? Bei CREATE VIEW kommt jedes mal ein Fehler, ich benutze MsSQL 7, das scheint das nicht zu unterstützen. Kann ich ein dreifaches JOIN machen? Ich habe kein php oder so zur Verfügung, nur MsSQL.

  1. Hallo,

    kannst Du mal kurz die Struktur Deiner Tabellen zugänglich machen. Ich denke, ich könnte Dir helfen.

    Gruß Frank

    1. sorry, die Benennung ist etwas "schwierig". ich habe

      1.)tblAttributeSet

      mit den Feldern:

      tblAttributeSetId
      intItemId

      2.)tblAttributeSetAttribute

      mit Feldern:

      tblAttributeSetAttribute
      intAttributeSetId
      intAttributeId

      3.) tblAttribute

      mit:

      tblAttributeId
      strTitle

      Dann habe ich ein SELECT tblAttributeSetAttribute.intAttributeId über ein JOIN von Table 1 und Table 2 gemacht mit

      JOIN ON
       tblAttributeSetAttribute.intAttributeSetId = tblAttributeSet.tblAttributeSetId

      gemacht. Ich will jetzt alle Einträge aus tblAttribute haben und möchte an einem zusätzlichen Feld blnPossible ablesen können, ob diese Row in dem vorherigen Select vorkam. Sorry, ich kann es nicht einfacher ausdrücken aber es wäre wirklich super, wenn du mir helfen könntest :)

      Gruß
      Michael

      1. Hallo Michael,

        Dein Problem ist in der Tat schwer zu verstehen. Wenn ich Deine Tabellenstruktur richtig interpretiere, kannst Du mit folgendem Statement die Daten aus alllen 3 Tabellen in einer Abfrage holen:

        SELECT * FROM tblAttributeSet,tblAttributeSetAttribute,tblAttribute WHERE intAttributeSetId = tblAttributeSetId AND
        intAttributeId = tblAttributeId

        Dann hättest Du alle Informationen da. Vielleicht kannst Du die WHERE-Bedingung noch um bestimmte Filter erweitern, die Du brauchst.

        Hoffe, das bringt Dich auf die richtige Schiene. Wenn ich Dich falsch verstanden habe, schicke mir mal die statements, die Du bisher auf die DB losgelassen hast.

        HTH

        Gruß Frank

        1. Hallo Frank,

          das hiflt mir schon mal weiter, danke. Mein Problem ist aber jetzt, dass ich aus dem dritten Table tblAttribute alle Einträge will, eine zusätzliche Spalte mit einer Funktion soll allerdings entprechend des SELECT-Statements, das du mir gegeben hast, auf true gesetzt werden. Hast du dazu noch ne Idee? Oder ist das Problem noch unklar?

          1. Hallo Michael,

            ... Oder ist das Problem noch unklar?

            Irgendwie schon. Gibt es in dieser Tabelle eine Spalte, in die der Wert geschrieben werden soll? Was ist das eigentliche Ziel=

            Gruß Frank

            1. Irgendwie schon. Gibt es in dieser Tabelle eine Spalte, in die der Wert geschrieben werden soll?

              Nein, die müsste ich erst anlegen. Also entweder zur laufzeit anlegen, ne temporäre Tabelle erstellen oder einen view, aber view scheint ja nicht zu gehen

              Was ist das eigentliche Ziel=

              Ich habe zwei Tables wo Infos über Attribute drinstehen. Aus den beiden Tables bekomme ich per SELECT einige IDs zurückgegeben. Jetzt will ich ALLE Attribute haben und will beim Ergebnis für jeden Eintrag abfragen können, ob er in dem ersten SELECT war.

              Äquivalentes Problem: Ich habe einen Table mit alles Bundesbürgern. Ich will jetzt eine Liste mit allen erstellen und in der Liste arbeitslose Frauen markieren. Dazu habe ich zwei Tables: "Frauen" und "Arbeitslos". Ein Select auf diese beiden Tables gibt mir 350.000 IDs zurück, die den IDs in der "Bundesbürger"-Tabelle entsprechen. Wie bekomme ich jetzt eine Liste mit allen Bundesbürgern, bei der ich für jeden eintrag auslesen kann, ob der Bürger eine arbeitslose Frau ist, ohne 80 Mio. SELECTs machen zu müssen?

              Gruß
              Michael

              1. Hallo Michael,

                Eigentlich soltest Du mit dem Join nur die 350.000 Einträge zurückbekommen, die Du als Ergebnis der ersten Abfrage erhältst.
                Um bei Deinem beispiel zu bleiben:

                Wenn das SELECT auf die beiden Tabellen "Frauen" und "arbeitslos" genau die Menge ID's an Bundesbürgern liefert, dann kommen auch nur die zugehörigen Infos der Bundesbürger dazu. Zusätzliche Datensätze kommen nich in das Resultset.

                HTH

                Gruß Frank

                PS: Falls ich immer noch etwas nicht verstanden habe, schicke mal den Code Deiner Procedure.

  2. Hi Michael

    SELECT irgendwas FROM Table1 JOIN Table2

    gibt 10 und 11 zurück.

    Table3 enthält Einträge mit den IDs 10,11 und 12. Jetzt will ich alle Einträge aus Table3 zurückgeben, allerdings soll eine zusätzliche Column blnPossible bei 10 und 11 auf true gesetzt sein, bei 12 auf false. Wie mache ich das?? Bei CREATE VIEW kommt jedes mal ein Fehler, ich benutze MsSQL 7, das scheint das nicht zu unterstützen. Kann ich ein dreifaches JOIN machen?

    Nur mal ein ungetesteter Versuch, eher pseudocode als reales SQL

    Select a.feld, is_null(c.feld) -- gibt es sowas wie is_null in MSSql?
      from a
           left outer join b on (a.key = b.key)
           left outer join c on (b.key = c.key) -- Verknüpfung aus deiner 2. Query
      where deine bedingungen

    Das müsste dir alles aus b geben. Dazu ist c.feld nur gesetzt,
    also nicht null falls eine Verknüfung zwischen a und b und von
    b nach c existiert. Der left outer join sagt, es ist mir
    egal ob in b od c was drinsteht, gib mir einfach alles was dazu
    passt und sonst null. Mit is_null (od wie das in MSSQL auch heisst)
    setzt du dann noch deinen Boolean.

    Gruss Daniela

    1. Hallo Daniela,

      Select a.feld, is_null(c.feld) -- gibt es sowas wie is_null in MSSql?
        from a
             left outer join b on (a.key = b.key)
             left outer join c on (b.key = c.key) -- Verknüpfung aus deiner 2. Query
        where deine bedingungen

      Das klingt irgendwie logisch, wenn ich es auch nicht komplett verstehe. ISNULL gibt es, ISNULL ( check_expression , replacement_value ) gibt replacement_value zurück, wenn check_expression = NULL ist.

      Ich verstehe allerdings nicht, was c.feld sein soll. Was für ein Feld soll ich da angeben?

      Gruß
      Michael

      1. Hi Michael

        Ich verstehe allerdings nicht, was c.feld sein soll. Was für ein Feld soll ich da angeben?

        Das ist dein Key aus Tabelle 3, dem Select was du angegeben hast (die
        mit dem Feld irgendwas), der müsste ja gefüllt sein wenn er vorhanden ist
        und sonst NULL.

        Gruss Daniela

        1. Hallo

          leider funktioniert das Skript so nicht:

          SELECT
           tblAttribute.strTitle,
           tblAttribute.intAttributeGroupId,
           tblAttribute.tblAttributeId,
           ISNULL(tblAttributeSet.tblAttributeSetId,1) AS blnPossible
          FROM
           tblAttribute
          LEFT OUTER JOIN
           tblAttributeSetAttribute
          ON
           (tblAttributeSetAttribute.intAttributeId = tblAttribute.tblAttributeId)
          LEFT OUTER JOIN
           tblAttributeSet
          ON
           (tblAttributeSetAttribute.intAttributeSetId = tblAttributeSet.tblAttributeSetId)
          WHERE tblAttributeSetAttribute.intAttributeId = 6  ORDER BY tblAttribute.intAttributeGroupId,tblAttributeSetAttribute.intAttributeId

          Wenn ich "6" als Wert reingebe, bekomme ich nur das Attribut 6 zurück :-( Tut mir leid, ich weiß, dass die TableNamen das ganze sehr unübersichtlich machen.

          Trotzdem noch eine Idee?

          1. Hallo

            lanngsam wird die Sache deutlicher. Zwei Sachen fallen mir auf:
            1. Du solltest wohl für Dein Problem statt des OUTER JOIN einen INNER JOIN verwenden.
            2. Du kannst statt des Wertes "6" folgendes einfügen:
              WHERE feld IN (SELECT * FROM ...) welches Dir Deinbe Schlüsselliste liefert.

            HTH

            Gruß Frank

            1. Hallo

              ein Kollege ist gerade wiedergekommen und hat's mit erklärt. Was ich gesucht hatte, war folgendes:

              CREATE PROCEDURE
               dbo.uspGetAttributesByAttributes
               @strAttributeIds varchar(500) AS

              DECLARE
               @strSQL varchar(1000)

              SET
                @strSQL = '
              SELECT
               tblAttribute.strTitle,
               tblAttribute.intAttributeGroupId,
               tblAttribute.tblAttributeId,
               CASE
                WHEN intAttributeId IS NULL THEN 0
                ELSE 1
               END AS blnIsPossible
              FROM
               tblAttributeSetAttribute
               JOIN tblAttributeSet ON tblAttributeSetId = intAttributeSetId
               RIGHT JOIN tblAttribute ON tblAttributeId = intAttributeId
              WHERE ('

              DECLARE
               @strWhere varchar(300)

              EXEC
               spb_Split @strAttributeIds, 'tblAttributeSetAttribute.intAttributeId', 1, @strWhere OUTPUT

              SET
               @strSQL = @strSQL + @strWhere + ')
              OR
               tblAttributeSetAttribute.intAttributeId IS NULL
              ORDER BY tblAttribute.intAttributeGroupId,tblAttributeSetAttribute.intAttributeId'

              EXEC (@strSQL)
              GO

              und das funktioniert :)

              thx a lot
              Gruß
              mhuhn