Odium: SQL-Anfrage liefert zu viele Daten...

Hallo,

ich habe ein kleines Problem mit einer SQL-Abfrage unter MS-SQL Server.
Ich habe mehrere Tabellen...
tblGeraete - diese Tabelle enthält einzelne Geräteinformationen
tblGerTyp - Tabelle enthält Typinformationen des Gerätes z.B. Pentium 200
tblGerKlasse - enthält Klasseninformationen des Gerätes z.B. Laserdrucker
tblHistorie - diese Tabelle enthält Historieninformationen zu den Geräten, hier können beliebig viele Informationen zu den einzelnen Geräten enthalten sein.

verknüpft sind alle diese Tabellen über das Feld Geraete_ID, dies ist die ID der Tabelle tblGeraete und wird in alle anderen Tabellen in die entsprechenden Datensätze eingesetzt.

Nun habe ich eine SQL-Abfrage, die mir von jedem Gerät die Bezeichnung, Klasse, Typ ,Seriennummer, MAC und die Anzahl der Einträge in der Tabelle Historie anzeigt...
Funktioniert alles in allem, aber ich erhalte zuviele Einträge...
Manche Geräte die mehrere Einträge in der tblHistorie haben, werden genauso oft angezeigt, aber mit unterschiedlicher Anzahl der Historieneinträge z.B. Gerät test123 hat 3 historieneinträge, nun erscheint in meiner abfrage das gerät drei mal... zweimal ist der angezeigte historienwert 1 und einmal 3.... manche erscheinen mehrfach aber immer mit dem hsitorienwert 1 und manache sind scheinbar OK...

hier mal die abfrage:

select distinct tblGeraete.Geraete_ID, tblGeraete.Seriennummer, tblGeraete.Verwaltungsbez1, tblGeraete.MAC, tblGerKlasse.Beschreibung, tblGerTyp.Beschreibung, tblHistorie.Ausg_am, tblGeraete.GerKlasse_ID, count(tblHistorie.Geraete_ID) from tblGeraete, tblGerKlasse, tblGerTyp, tblHistorie WHERE tblGeraete.GerKlasse_ID = tblGerKlasse.GerKlasse_ID AND tblGeraete.GerTyp_ID = tblGerTyp.GerTyp_ID AND tblGeraete.Geraete_ID = tblHistorie.Geraete_ID GROUP BY tblGeraete.Geraete_ID, tblGeraete.Seriennummer, tblGeraete.Verwaltungsbez1, tblGeraete.MAC, tblGerKlasse.Beschreibung, tblGerTyp.Beschreibung, tblHistorie.Ausg_am, tblGeraete.GerKlasse_ID ORDER BY tblGeraete.GerKlasse_ID, tblGeraete.Verwaltungsbez1, tblGeraete.Geraete_ID

die große anzahl der splaten in der group by klausel liegt daran, das sich der sql-server aufgeregt hat, das bei einem count(Aggregatfunktion) die werte gruppiert werden müssen...so hab ich der reihenfolge der fehlermeldungen die felder ins group by aufgenommen....

hat wer einen plan, was hier zu machen ist?

Momentan weiß ich nicht weiter....

Vielen Dank

Odium

  1. Hallo Odium,

    Versuch mal dies:

    select tblGeraete.Geraete_ID, MAX(tblGeraete.Seriennummer),
    MAX(tblGeraete.Verwaltungsbez1), MAX(tblGeraete.MAC, tblGerKlasse.Beschreibung),
    MAX(tblGerTyp.Beschreibung), MAX(tblHistorie.Ausg_am), MAX(tblGeraete.GerKlasse_ID),
    count(tblHistorie.Geraete_ID)
    from tblGeraete, tblGerKlasse, tblGerTyp, tblHistorie
    WHERE tblGeraete.GerKlasse_ID = tblGerKlasse.GerKlasse_ID AND tblGeraete.GerTyp_ID = tblGerTyp.GerTyp_ID
    AND tblGeraete.Geraete_ID = tblHistorie.Geraete_ID
    GROUP BY tblGeraete.Geraete_ID
    ORDER BY tblGeraete.GerKlasse_ID, tblGeraete.Verwaltungsbez1, tblGeraete.Geraete_ID

    Gruß Frank

    1. Hallo Frank,

      Dein Vorschlag gibt aber nicht unbedingt das gewünschte Resultat wieder, oder? Angenommen die Geräte mit ID 3-5 wurden ausgemustert und aus der DB gelöscht. count() würde dann fürs Intervall 0-10 auf 7 kommen. max() aber auf 10.

      Grüße aus Würzburg
      Julian

      1. Hallo Julian,

        Das MAX() ist eigentlich nur da, da man beim eine GROUP BY über eine Spalte die anderen Spalten außerhalb des GROUP BY in eine Aggregatsfunktion packen muß. Da ich die Frage so interpretiere, daß es Odium nur auf die Anzahlder Historieneinträge ankommt und es sich bei den Feldern wie Beschreibung oder so um einen einheitliche Wert je ID handelt verwende ich dann das MAX().

        Hätte ich vielleicht ein wenig kommentieren sollen.

        Gruß Frank

  2. Hallo,

    select distinct tblGeraete.Geraete_ID, tblGeraete.Seriennummer, tblGeraete.Verwaltungsbez1, tblGeraete.MAC, tblGerKlasse.Beschreibung, tblGerTyp.Beschreibung, tblHistorie.Ausg_am, tblGeraete.GerKlasse_ID, count(tblHistorie.Geraete_ID) from tblGeraete, tblGerKlasse, tblGerTyp, tblHistorie WHERE tblGeraete.GerKlasse_ID = tblGerKlasse.GerKlasse_ID AND tblGeraete.GerTyp_ID = tblGerTyp.GerTyp_ID AND tblGeraete.Geraete_ID = tblHistorie.Geraete_ID GROUP BY tblGeraete.Geraete_ID, tblGeraete.Seriennummer, tblGeraete.Verwaltungsbez1, tblGeraete.MAC, tblGerKlasse.Beschreibung, tblGerTyp.Beschreibung, tblHistorie.Ausg_am, tblGeraete.GerKlasse_ID ORDER BY tblGeraete.GerKlasse_ID, tblGeraete.Verwaltungsbez1, tblGeraete.Geraete_ID

    Als erstes möchte ich Dir empfehlen, auch SQL-Statements leserlicher zu formatieren. Keine mir bekannte Datenbank stößt sich an einer geeigneten Foprmatierung, für den Leser ist es jedoch ziemlich mühsam bei so einem Statement durchzublicken.

    Du verschweigst uns zwar die Feldbedeutungen, aber ich denke doch, daß
    tblHistorie.Ausg_am der Grund Deines Problems ist. ES aknn durchaus sein, daß das so sein muß, wenn jedoch dieses Feld unterchiedliche Werte aufweißt, dann bekommst Du dadurch mehrere Datensätze zurück.

    Grüße
      Klaus

  3. Hallo Andre,

    verknüpft sind alle diese Tabellen über das Feld Geraete_ID, dies ist die ID der Tabelle tblGeraete und wird in alle anderen Tabellen in die entsprechenden Datensätze eingesetzt.

    Funktioniert alles in allem, aber ich erhalte zuviele Einträge...
    Manche Geräte die mehrere Einträge in der tblHistorie haben, werden genauso oft angezeigt, aber mit unterschiedlicher Anzahl der Historieneinträge z.B. Gerät test123 hat 3 historieneinträge, nun erscheint in meiner abfrage das gerät drei mal... zweimal ist der angezeigte historienwert 1 und einmal 3.... manche erscheinen mehrfach aber immer mit dem hsitorienwert 1 und manache sind scheinbar OK...

    hier mal die abfrage:

    select distinct tblGeraete.Geraete_ID, tblGeraete.Seriennummer, tblGeraete.Verwaltungsbez1, tblGeraete.MAC, tblGerKlasse.Beschreibung, tblGerTyp.Beschreibung, tblHistorie.Ausg_am, tblGeraete.GerKlasse_ID, count(tblHistorie.Geraete_ID) from tblGeraete, tblGerKlasse, tblGerTyp, tblHistorie WHERE tblGeraete.GerKlasse_ID = tblGerKlasse.GerKlasse_ID AND tblGeraete.GerTyp_ID = tblGerTyp.GerTyp_ID AND tblGeraete.Geraete_ID = tblHistorie.Geraete_ID GROUP BY tblGeraete.Geraete_ID, tblGeraete.Seriennummer, tblGeraete.Verwaltungsbez1, tblGeraete.MAC, tblGerKlasse.Beschreibung, tblGerTyp.Beschreibung, tblHistorie.Ausg_am, tblGeraete.GerKlasse_ID ORDER BY tblGeraete.GerKlasse_ID, tblGeraete.Verwaltungsbez1, tblGeraete.Geraete_ID

    Ich nehme mal an, dass die zu große Anzahl an Datensätze, die dieses SQL-Statement zurückgibt daranliegt, dass du das Feld tblHistorie.Ausg_am selektierst und darüber gruppierst.
    Wenn zu einer GeraeteID 3 Einträge im tblHistorie vorliegen,
    haben diese wahrscheinlich alle ein unterschiedliches Ausgabedatum (ich nehme an Ausg_am = Ausgabedatum), also erhältst du auch 3 Datensätze aus deiner SQL-Abfrage. Lass das Feld einfach weg, oder selektiere das Maximum dieses Feldes, wie Frank Jonas vorgeschlagen hat.

    Gruß
    Stefan

  4. Hallo,

    danke für Eure Antworten.

    Es lag wirklich an dem Feld Ausg_am.

    das natürlich in der historie mehrfach, unterschiedlich vorkommen kann....
    wenn ich bei dem Kriterium "from" tblHistorie nur so angehangen habe, ohne daraus ein feld zu selektieren wurden mir x-viele gleiche datensätze angezeigt, so hatte ich das ausg_von mit aufgenommen um dies zu vermeiden...dies führte dann im weiteren verlauf zu diesem fehler...

    je nach "ankreuzungen" in der entsprechenden suchmaske wurde die tabelle tblHistorie nämlich gebraucht oder nicht, was dann aber bei aufnahme des count hinfällig wurde....

    also vielen Dank nochmal...

    ich hatte wirklich nicht erwartet, dass ihr euch die mühe macht und das sql-statement so auseinandernehmt....

    herzlich dank, man sieht hier sind profis am werk...

    Odium

    1. Hallo,

      ich habe leider doch noch ein kleines Problem...

      Die Abfrage funktioniert soweit, aber natürlich bekomme ich durch die Verknüpfung tblGeraete.Geraete_ID = tblHistorie.Geraete_ID in der where-klausel nur die datensätze angezeigt, die auch mindestens einen eintrag in der tabelle tblHistorie enthalten alle geräte die zwar existieren, aber keinen historie eintrag enthalten werden verschwiegen...
      lasse ich diesen verknüpfung komplett weg erscheint zu jedem einzelnen gerät ein historie-eintrag von 786, genauso viel wie einträge in der historie-tabelle enthalten sind

      nun habe ich probiert, mit einem Right Outer Join:
      tblGeraete.Geraete_ID =* tblHistorie.Geraete_ID

      zu verknüpfen, aber dies ergibt einen fehler, da die tabelle innerhalb des join nicht mit anderen tabellen (tblGerKlasse, tblGerTyp) verknüpft sein darf, also würden mir diese bezeichnungen fehlen...bei näherer überlegung ist diese mimik wohl auch für den ausguss...

      also ich weiß nicht recht weiter...am einfachsten wäre es wohl innerhalb der schleife der ausgabe der geräte (ohne count) jedesmal den count aufs einzelen gerät zu starten, aber dies ist höchst unperformant für die datenbank...
      hier nochmal die abfrage:

      select distinct tblGeraete.Geraete_ID,
      tblGeraete.Seriennummer,
      tblGeraete.Verwaltungsbez1,
      tblGeraete.MAC,
      tblGerKlasse.Beschreibung,
      tblGerTyp.Beschreibung,
      tblGeraete.GerKlasse_ID,
      count(tblHistorie.Geraete_ID)

      FROM tblGeraete, tblGerKlasse, tblGerTyp, tblHistorie

      WHERE tblGeraete.GerKlasse_ID = tblGerKlasse.GerKlasse_ID
      AND tblGeraete.GerTyp_ID = tblGerTyp.GerTyp_ID
      AND tblGeraete.Geraete_ID = tblHistorie.Geraete_ID

      GROUP BY tblGeraete.Geraete_ID,
      tblGeraete.Seriennummer,
      tblGeraete.Verwaltungsbez1,
      tblGeraete.MAC,
      tblGerKlasse.Beschreibung,
      tblGerTyp.Beschreibung,
      tblGeraete.GerKlasse_ID

      ORDER BY tblGeraete.GerKlasse_ID,
      tblGeraete.Verwaltungsbez1,
      tblGeraete.Geraete_ID

      ich weiß momentan nicht, wie ich das bewerkstelligen soll...
      ich hoffe jemand hat noch einen schlauen tipp für mich...

      Vielen Dank

      Odium

      1. Hallo, Odium

        versuch mal LEFT OUTER JOIN mit dem Stern vor dem "="

        Gruß Frank