Localhorst: Sql Abfrage mit Gruppierung

Hallo Forum,

ich habe eine Tabelle die wie folgt aufgebaut ist.

schnittnummer   int(10)    (Zahl von 0 - ca 10000,Pri. Key)
gruppe  int(10)
status tynint(1)
user_id int(10)
datum   int(20)

1996;0;0;0;;              Block 1

2011;1;2;1;1168870968;    Block 2 (gleiche Gruppennr.)
2026;1;2;1;1168870968;
2041;1;2;1;1168870968;
2056;1;2;1;1168870968;

2071;0;2;1;1168871122;    Block 3
2086;0;2;1;1168870968;
2101;0;2;1;1168870968;
2116;0;0;1;1168870434;

2131;2;2;1;1168871029;    Block 4 (gleiche Gruppennr.)
2146;2;2;1;1168871029;
2161;2;2;1;1168871029;
2176;2;2;1;1168871029;

Die Zeilen des zweiten und des letzten Blocks haben jeweils die selbe Gruppe.

Frage:
Ist es möglich, in einer SQL Abfrage von den Blocks, die jeweils die selbe Gruppennummer haben die kleinste und größte Schnittnummer zu bekommen. Wenn die Gruppennummer 0 ist soll direkt die Schnittnummer raus kommen.

Das Ergebnis sollte also wie folgt aussehen
1996;    (Erster Block, Gruppe 0 also normal ausgeben)

2011;    (Min Schnittnummer von zweitem Block, Gruppe 1)
2056;    (Max Schnittnummer von zweitem Block, Gruppe 1)
2071;
2086;
2101;
2116;
2131;    (Min Schnittnummer von viertem Block, Gruppe 2)
2176;    (Max Schnittnummer von viertem Block, Gruppe 2)

Ich denke, dass es evtl. mit dem group Befehl irgentwie gehen könnte, aber leider schaue ich schon zu lange drauf um noch eine Chance zu haben eine Lösung zu finden. Für etwas Hilfe wäre ich sehr dankbar.

Mit freundlichen Grüßen
Localhorst

  1. Hallo,

    Frage:
    Ist es möglich, in einer SQL Abfrage von den Blocks, die jeweils die selbe Gruppennummer haben die kleinste und größte Schnittnummer zu bekommen. Wenn die Gruppennummer 0 ist soll direkt die Schnittnummer raus kommen.

    D.h. also, dass es eine unterschiedliche Behandlung für Datensätze mit Gruppennummer 0 und solech mit einer anderen Gruppennummer gibt.
    Erstere, so verstehe ich das zumindest, sollen ohne Gruppierung behandelt werden, zweitere jedoch mit einer Gruppierung unter Einbeziehung von Aggregat-Funktionen:

    SELECT x FROM
    (
    SELECT x FROM tabelle
     WHERE y = 0
    UNION
    SELECT MIN(x) FROM tabelle
     WHERE y >0
    UNION
    SELECT MAX(x) FROM tabelle
     WHERE y >0
    )
    ORDER BY x ASC

    Das wäre eine mögliche Variante unter der Voraussetzung, dass die Datenbank diese Syntax versteht. Da Du nicht angegeben hast, welche Datenbank und vroi allem welche Version dieser Datenbank Du verwendest, gehe ich einmal davon aus, dass dem so ist.

    Grüße
      Klaus

    1. Hallo und Danke für deine Antwort, ich versuche gerade diese um zu setzen.

      D.h. also, dass es eine unterschiedliche Behandlung für Datensätze mit Gruppennummer 0 und solech mit einer anderen Gruppennummer gibt.
      Erstere, so verstehe ich das zumindest, sollen ohne Gruppierung behandelt werden, zweitere jedoch mit einer Gruppierung unter Einbeziehung von Aggregat-Funktionen:

      .....

      Das wäre eine mögliche Variante unter der Voraussetzung, dass die Datenbank diese Syntax versteht. Da Du nicht angegeben hast, welche Datenbank und vroi allem welche Version dieser Datenbank Du verwendest, gehe ich einmal davon aus, dass dem so ist.

      Ich benutze eine lokale MySQL Datenbank der Version  5.0.24a

      Gruß
      Localhorst

    2. SELECT x FROM
      (
      SELECT x FROM tabelle
      WHERE y = 0
      UNION
      SELECT MIN(x) FROM tabelle
      WHERE y >0
      UNION
      SELECT MAX(x) FROM tabelle
      WHERE y >0
      )
      ORDER BY x ASC

      Habe deine Abfrage Umgebaut und es kommt leider ein Fehler.
      Folgende Ausgabe bekomme ich von PHPmyAdmin

      Fehler

      SQL-Befehl: Dokumentation

      SELECT schnittnummer
      FROM 16_96(

      SELECT schnittnummer
      FROM 16_96
      WHERE gruppe =0
      UNION
      SELECT MIN( schnittnummer )
      FROM 16_96
      WHERE gruppe >0
      UNION
      SELECT MAX( schnittnummer )
      FROM 16_96
      WHERE gruppe >0
      )
      ORDER BY schnittnummer ASC

      MySQL meldet: Dokumentation
      #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(
      SELECT schnittnummer FROM 16_96
      WHERE gruppe = 0
      UNION
      SELECT MIN(schnitt' at line 2

      1. Hallo,

        SELECT x FROM
        (
        [...]
        )
        ORDER BY x ASC

        versus

        SELECT schnittnummer
        FROM 16_96(
        [...]
        )
        ORDER BY schnittnummer ASC

        Was ist, ausser den Bezeichnungen und Zeilenumbrüchen anders?

        Tip: es hat was mit 16_96 zu tun;-)

        Grüße
          Klaus

  2. Hoi,

    ich würde mal vorschlagen:

    Baue drei einzelne Abfragen, in denen du deine Ergebnismenge genau
    beschreibst mithilfe von MAX(..) bzw. MIN(..), GROUP BY und WHERE
    und füge sie mittels UNION aneinander.

    Ciao, Frank

  3. yo,

    schnittnummer   int(10)    (Zahl von 0 - ca 10000,Pri. Key)

    das ist nicht ideal, einen sogenannten sprechenden schlüssel als primary key zu benutzen. wenn es keine gründe dafür gibt, zum beispiel vorgabe des kunden, dann nimm lieber einen künstlichen schlüssel und mach für die schnittnummer eine extra spalte, die unique und not null contraints besitzt.

    Die Zeilen des zweiten und des letzten Blocks haben jeweils die selbe Gruppe.

    das kann ich nicht erkennen, ist nicht der zweite wert in den beispieldaten die gruppenzuordnung oder irre ich mich da ?

    Ist es möglich, in einer SQL Abfrage von den Blocks, die jeweils die selbe Gruppennummer haben die kleinste und größte Schnittnummer zu bekommen. Wenn die Gruppennummer 0 ist soll direkt die Schnittnummer raus kommen.

    ja, das ist nicht besonders schwer, ich würde keinen union wie bereits vorgeschlagen benutzen, da du damit keine felxibilität erreichst, wenn mehr gruppen dazu kommen.

    besser sind "korrelierenden unterabfragen", in der die ganze magic steckt:

    SELECT DISTINCT tab1.hier_spalten_zur_ausgabe_angeben
    FROM tablle tab1
    WHERE tab1.schnitternummer = (SELECT MAX(tab2.schnittnummer) FROM tabelle tab2 WHERE tab1.gruppe = tab2.gruppe)
    OR tab1.schnitternummer = (SELECT MIN(tab3.schnittnummer) FROM tabelle tab3 WHERE tab1.gruppe = tab3.gruppe)

    Ilja

    1. Hallo,

      das ist nicht ideal, einen sogenannten sprechenden schlüssel als primary key zu benutzen. wenn es keine gründe dafür gibt, zum beispiel vorgabe des kunden, dann nimm lieber einen künstlichen schlüssel und mach für die schnittnummer eine extra spalte, die unique und not null contraints besitzt.

      Ich habe bis jetzt noch nie verstanden, warum man in einer Tabelle, in der eine Spalte existiert, die einen Datensatz bereits eindeutig identifiziert (was ja die Aufgabe eines Primär-Schlüssels sein soll), noch zusätzlich eine zweite Spalte anlegen soll, deren Wert dann, so vermute ich mal, per Sequenz oder AutoID oder wie auch immer erzeugt wird.
      Hat das nur mit "Das macht man halt so" zu tun, oder gibt es einen triftigen Grund dafür.
      Ich sehe nämlich in der Verwendung von mehreren Unique Keys, wobei jeder davon nur eine jeweils eine Spaltge betrifft, eher nachteilig, weil mehr Verwaltungsaufwand.

      SELECT DISTINCT tab1.hier_spalten_zur_ausgabe_angeben
      FROM tablle tab1
      WHERE tab1.schnitternummer = (SELECT MAX(tab2.schnittnummer) FROM tabelle tab2 WHERE tab1.gruppe = tab2.gruppe)
      OR tab1.schnitternummer = (SELECT MIN(tab3.schnittnummer) FROM tabelle tab3 WHERE tab1.gruppe = tab3.gruppe)

      Naja, aber eigentlich wollte der OP MIN und MAX nur von den Gruppen > 0 haben, während für die Gruppe == 0 alle Werte ausgegeben werden sollten.
      Abgesehen davon finde ich, dass das UNION-Statement leichter zu lesen ist, abgesehen von allfälligen Performance-Aspekten, die ich so einfach aus der Hüfte aber nicht beantworten könnte.

      Grüße
        Klaus

      1. yo,

        Ich habe bis jetzt noch nie verstanden, warum man in einer Tabelle, in der eine Spalte existiert, die einen Datensatz bereits eindeutig identifiziert (was ja die Aufgabe eines Primär-Schlüssels sein soll), noch zusätzlich eine zweite Spalte anlegen soll, deren Wert dann, so vermute ich mal, per Sequenz oder AutoID oder wie auch immer erzeugt wird.

        ja hat es, wobei es nicht darum geht, mehr als einen unique und nicht zu vergessen not null spalte zu haben, sondern darum, keine "inhalte" in den pk zu legen. das problem dabei ist, dass sich die inhalte im laufe der zeit ändern können und man dann nicht nur den sprechenden schlüssel ändern muss, sondern aller wahrschenilichkeit auch alle anderen spalten, wo er als fremdschlüssel verwendet wird.

        ein beispiel dafür wäre eine autonummer. diese ist sicherlich unique und not null, erfüllt also beide kritereien eines pk. aber sie kann sich für eine und dasselbe auto im laufe der zeit ändern. und das wäre schlecht, wohingegen eine künstliche spalte keine probleme damit hätte.

        abgesehen von allfälligen Performance-Aspekten, die ich so einfach aus der Hüfte aber nicht beantworten könnte.

        die performance von unterabfragen hat einen schlechten ruf. in der praxis sind sie aber in regel viel schneller, besonders im vergleich zu UNION, der meiner meinung nach in diesem fall nicht nur unflexibler ist, sondern auch eine sortierung der gesamten ergebnismenge nach sich zieht, da er distincte werte auschließt, mal davon abgesehen, ob das überhaupt gewollt ist.

        Ilja

        1. Hallo,

          ja hat es, wobei es nicht darum geht, mehr als einen unique und nicht zu vergessen not null spalte zu haben, sondern darum, keine "inhalte" in den pk zu legen. das problem dabei ist, dass sich die inhalte im laufe der zeit ändern können und man dann nicht nur den sprechenden schlüssel ändern muss, sondern aller wahrschenilichkeit auch alle anderen spalten, wo er als fremdschlüssel verwendet wird.

          Dann heisst das ja wohl, dass eine der Eigenschaften eines Primärschlüssels dessen unveränderlichkeit über die gesamte Lebensdauer eiens Datensatzes ist. Wenn das garantiert wäre, würde auch nichts dagegen sprechen, dass, wie Du es nennst, Inhalte im PK hinterlegt sind.

          ein beispiel dafür wäre eine autonummer. diese ist sicherlich unique und not null, erfüllt also beide kritereien eines pk. aber sie kann sich für eine und dasselbe auto im laufe der zeit ändern.

          Naja, eine Fahrgestellnummer ist ebenfalls eindeutig und nicht veränderbar (ausser kriminelle Elemente sind am Werk, aber da frage ich mich, ob die dann eine Datenbank einsetzen;-). Also würde ich eher die hernehmen.

          Wie oben gesagt, denke ich auch, dass der PK während der Lebenszeit nicht veränderlich sein soll. _Wie_ der Wert jedoch generiert wird, und ob er so 'nebenbei' auch noch eine Bedeutung hat, ist imho unerheblich. Diese Eigenschaft hatten allerdings Identifikationsnummern auch schon in de Pre-IT-Ära.

          die performance von unterabfragen hat einen schlechten ruf. in der praxis sind sie aber in regel viel schneller, besonders im vergleich zu UNION, der meiner meinung nach in diesem fall nicht nur unflexibler ist, sondern auch eine sortierung der gesamten ergebnismenge nach sich zieht, da er distincte werte auschließt, mal davon abgesehen, ob das überhaupt gewollt ist.

          Naja, UNION macht in der Regel ein implizites DISTINCT, welches man mit UNION ALL dann meist auch verhindern kann.
          Und, wie schon gesagt, ich könnte das rein aufgrund des Statements nicht wirklich entscheiden, was schneller sein würde.

          Ausserdem, was meinst Du mit unflexibler? Das kann ich auch nicht sehen. Ich bin der Meinung, dass es irgendwann einen Punkt gibt, wo man für eine bestimmte Aufgabe ein bestimmtes Staement braucht, und wenn sich die Rahmenbedingungen ändern, ändert man auch das Statement.

          Grüße
            Klaus

          1. yo,

            die frage kommt von der anderen seite, nämlich welchen nachteil habe ich, wenn ich einen künstlichen pk einsetze ?

            die antwort ist einfach, gar keinen nachteil, gegenüber einer aussage, ich bin mir heute sicher, dass sich der pk mit inhalt nicht verändern wird. aber morgen.....

            mit anderen worten, mit der einen methode habe ich 100% sicherheit, mit der anderen muss ich aussagen über die zukunft treffen.

            Ilja