Tannenbaum: MS SQL - Abfrage, Hilfe

Hallo,

ich brauche eure Hilfe, und zwar:

Ich habe 2 Datenbanktabellen und es gibt keine Primärschlüssel o.ä.:

1. Tabelle
_____________________________________________________________________
  Kennziffer        Name

1             Bauer
      2             Schmidt
      3             Schumacher

2. Tabelle
_____________________________________________________________________
  Kennziffer      Von                      Bis                   Tage
      1           01.01.2005 00:10:00      02.02.2005 00:30:01     4
      2           04.01.2005 00:35:00      06.02.2005 00:20:00     24
      1           05.01.2005 00:30:00      07.02.2005 00:30:00     3
      1           04.01.2005 00:30:00      12.02.2005 00:40:00     45
      3           07.01.2005 00:35:00      22.02.2005 00:30:06     66
      1           08.01.2005 00:38:00      21.02.2005 00:20:00     23
      3           08.01.2005 00:30:00      06.02.2005 00:12:08     45

Ich brauche eine Abfrage, die folgendes liefert:
Die Namen einzeln, also 1x "Bauer", 1x "Schmidt", 1x "Schumacher" und nicht 4x "Bauer", 1x "Schmidt" und 2x "Schumacher".
Den größten Eintrag "Von", also max(Von), und die dazugehörige "Bis" und "Tage".

Das muss dann so aussehen:

Name             Von                        Bis               Tage

Bauer         08.01.2005 00:38:00      21.02.2005 00:20:00     23
Schmidt       04.01.2005 00:35:00      06.02.2005 00:20:00     24
Schumacher    08.01.2005 00:30:00      06.02.2005 00:12:08     45

Danke schon mal!

  1. Hi Tannenbaum,

    Das muss dann so aussehen:

    Name             Von                        Bis               Tage

    Bauer         08.01.2005 00:38:00      21.02.2005 00:20:00     23
    Schmidt       04.01.2005 00:35:00      06.02.2005 00:20:00     24
    Schumacher    08.01.2005 00:30:00      06.02.2005 00:12:08     45

    Ich denke mal du musst erst alle max(Von) raussuchen und dann in ein zweites  SELECT einbauen, wo du dann die anderen Sachen dazu raussuchst (mit einem JOIN auf tabelle1.name)

    Es könnte vielleicht auch irgendwie in einem SELECT gehen irgendwie indem du  irgendwie das max(von) jeder person raussuchst und die Tabelle2 mit sich selbst joinst oder so... Keine Ahnung, ganz so gut kenn ich mich mit MySQL nicht aus.

    Gruß, Marian

    1. Hallo

      Das muss dann so aussehen:

      Name             Von                        Bis               Tage

      Bauer         08.01.2005 00:38:00      21.02.2005 00:20:00     23
      Schmidt       04.01.2005 00:35:00      06.02.2005 00:20:00     24
      Schumacher    08.01.2005 00:30:00      06.02.2005 00:12:08     45

      Ich denke mal du musst erst alle max(Von) raussuchen und dann in ein zweites  SELECT einbauen, wo du dann die anderen Sachen dazu raussuchst (mit einem JOIN auf tabelle1.name)

      Iljas Lösungsvorschlag aus dem verlinkten Archivthread sollte auch hier anwendbar sein.

      Keine Ahnung, ganz so gut kenn ich mich mit MySQL nicht aus.

      Das ist nicht schlimm, schliesslich geht es hier nicht um MySQL, was von Vorteil ist. Denn der MS SQL Server unterstützt Subselects, bei MySQL müsste es schon Version 4.1 oder größer sein.

      Freundliche Grüße

      Vinzenz

      1. Hi Vinzenz Mai,

        Iljas Lösungsvorschlag aus dem verlinkten Archivthread sollte auch hier anwendbar sein.

        https://forum.selfhtml.org/?t=119749&m=768457

        Keine Ahnung, ganz so gut kenn ich mich mit MySQL nicht aus.

        Das ist nicht schlimm, schliesslich geht es hier nicht um MySQL, was von Vorteil ist. Denn der MS SQL Server unterstützt Subselects, bei MySQL müsste es schon Version 4.1 oder größer sein.

        Hab ich gar nicht gesehen! Aber es gibt jetzt schon MySQL5 - da sollte man dann wenigstens so langsam mal Version 4 haben.
        Außerdem: so wenig Micro$oft wie möglich ;~)

        Gruß, Marian

        1. Hallo Marian,

          bei MySQL müsste es schon Version 4.1 oder größer sein.

          Hab ich gar nicht gesehen! Aber es gibt jetzt schon MySQL5 - da sollte man dann wenigstens so langsam mal Version 4 haben.

          wie bereits im ersten Abschnitt erwähnt, reicht eine Version 4.0.x nicht aus, es muss 4.1.x sein.

          4.0.15 ist noch im Einsatz. Es soll auch Hoster geben, die aus Lizenzgründen noch die Version 3.23.18 im Einsatz haben.

          Freundliche Grüße

          Vinzenz

          1. Hi Vinzenz Mai,

            bei MySQL müsste es schon Version 4.1 oder größer sein.

            Hab ich gar nicht gesehen! Aber es gibt jetzt schon MySQL5 - da sollte man dann wenigstens so langsam mal Version 4 haben.

            wie bereits im ersten Abschnitt erwähnt, reicht eine Version 4.0.x nicht aus, es muss 4.1.x sein.

            Mein ich ja. Tippfehler.

            Gruß, Marian

  2. yo,

    wie Vinzenz schon richtig anmerkte, sollte auch hier eine korrelierende unterabfrage zum gewünschten ergebnis führen.

    SELECT t1.kennziffer, t1.name, t2.von, t2.bis, t2.tage
    FROM tabelle1 AS t1, tabelle2 AS t2
    WHERE t1.kennziffer = t2.kennziffer
    AND t2.von = (SELECT MAX(t3.von) FROM tabelle2 AS t3 WHERE t2.kennziffer = t3.kennziffer)

    anzumerken ist dabei, dass bei datensätzen mit den gleichen max datums-wert auch mehrere ergebnisse pro person aufgelistet werden.

    Ilja

    1. SELECT t1.kennziffer, t1.name, t2.von, t2.bis, t2.tage
      FROM tabelle1 AS t1, tabelle2 AS t2
      WHERE t1.kennziffer = t2.kennziffer
      AND t2.von = (SELECT MAX(t3.von) FROM tabelle2 AS t3 WHERE t2.kennziffer = t3.kennziffer)

      Alles klar. Ich mach das so, da es doch keine doppelten "max(Von)" vorkommen sollen. Danke ;)

  3. Habe immer noch keine Lösung :(

    1. Hallo

      Habe immer noch keine Lösung :(

      Warum nicht? Es wurde eine funktionierende Lösung vorgeschlagen, die Du nur an Dein Problem anzupassen brauchst. MS SQL-Server hat jedenfalls keine Probleme mit Subselects.

      Was hast Du versucht, woran bist Du gescheitert?

      Freundliche Grüße

      Vinzenz

      1. Was hast Du versucht, woran bist Du gescheitert?

        Ich kriege zwar Datensätze mit Name + max(Von) + Bis + Tage, aber wenn gleiche Einträge bei Bis oder Tage enthalten sind, werden die Datensätze mehrfach angezeigt.
        z.B.

        max(von)
        Bauer         08.01.2005 00:38:00      21.02.2005 00:20:00     23
        Bauer         08.01.2005 00:38:00      22.02.2005 00:20:00     23
        Bauer         08.01.2005 00:38:00      22.02.2005 00:20:00     40

        1. Hallo

          Was hast Du versucht, woran bist Du gescheitert?

          Ich kriege zwar Datensätze mit Name + max(Von) + Bis + Tage, aber wenn gleiche Einträge bei Bis oder Tage enthalten sind, werden die Datensätze mehrfach angezeigt.
          z.B.

          max(von)
          Bauer         08.01.2005 00:38:00      21.02.2005 00:20:00     23
          Bauer         08.01.2005 00:38:00      22.02.2005 00:20:00     23
          Bauer         08.01.2005 00:38:00      22.02.2005 00:20:00     40

          Ja, das hatte Ilja bereits erwähnt, dass dieses Ergebnis zu erwarten ist. Für diesen Fall benötigst Du ein weiteres Kriterium, das den von Dir gewünschten Datensatz ermittelt. Dieses Kriterium kannst Du genauso einbauen wie das erste.

          Freundliche Grüße

          Vinzenz

          1. Hi,

            ja, so wie Ilja die Abfrage formuliert hat ist das verständlich.

            Vielleicht sollte man keine Unterabfrage in der Where-Klausel verwenden,
            sondern eine Parallel-Abfrage, die bereits nach Kennziffer gruppiert.

            Ich habe mal die Tabellen in Users und Actity umbenannt ... damit es
            anschaulicher wird.

              
            SELECT A.Kennziffer,  
                   C.Name,  
                   A.Von,  
                   A.Bis,  
                   A.Tage  
            FROM Activity AS A,  
                 (SELECT D.Kennziffer,  
                         Max(Von) AS max_von  
                  FROM Activity D  
                  GROUP BY D.Kennziffer) AS B,  
                 Users AS C  
            WHERE A.Kennziffer = B.Kennziffer  
            AND   A.Von = B.max_von  
            AND   C.Kennziffer = A.Kennziffer  
            ORDER BY A.Kennziffer  
            
            

            Alternativ wäre in Erwägung zu ziehen, für die Tabelle Activity einen
            Primärschlüssel einzuführen um so einen einzelnen Eintrag sehr schnell
            und effektiv bei der Hand zu haben.

            Ciao, Frank

            PS: Vielen Dank für die Mittagspausenablenkung ;)

  4. du mußt die 'vielen ergebniszeilen' aggregieren.

    SELECT t1.Name, MAX(t2.Von), t2.Bis, t2.Tage
    FROM tabelle1 t1 JOIN tabelle2 t2 USING(Kennziffer)
    GROUP BY t1.Name, t2.Bis, t2.Tage
    ORDER BY t1.Name ASC

    sollte ausreichen

    1. Hallo fanelf,

      SELECT t1.Name, MAX(t2.Von), t2.Bis, t2.Tage
      FROM tabelle1 t1 JOIN tabelle2 t2 USING(Kennziffer)
      GROUP BY t1.Name, t2.Bis, t2.Tage
      ORDER BY t1.Name ASC

      nein, Iljas Lösung ist richtig :-)
      Deine Lösung würde wieder zu mehreren Einträgen je Name führen, was laut Ausgangsposting nicht gewünscht ist.

      Die Aufgabenstellung lautet:

      Gib mir aus Tabelle 1 den "Namen",
      aus Tabelle 2 die Spalten "Von", "Bis" und "Tage",
      aber zu jeder "Kennziffer" nur die Zeile mit dem höchsten Wert in der Spalte "Tage". Genau dies liefert der Vorschlag von Ilja, wobei Ilja korrekt hinzugefügt hat, dass es im Falle von doppelten Max-Werten auch wiederum zu doppelten Einträgen kommen kann.

        
      SELECT  
        t1.name,  
        t2.von,  
        t2.bis,  
        t2.tage  
      FROM tabelle1 AS t1  
      INNER JOIN tabelle2 AS t2  
      ON t1.kennziffer = t2.kennziffer  
      WHERE t2.von = (  
          SELECT MAX(t3.von) FROM tabelle2 AS t3    -- kann bei Gleichheit zu  
          WHERE t2.kennziffer = t3.kennziffer       -- Mehrfacheinträgen führen  
      )
      

      Das einzige Problem stellt die Anpassung dieses Statements an die tatsächlich vorhandenen Tabellennamen und ggf. Spaltennamen dar.

      Freundliche Grüße

      Vinzenz

      1. Hallo,

        Genau dies liefert der Vorschlag von Ilja, wobei Ilja korrekt hinzugefügt hat, dass es im Falle von doppelten Max-Werten auch wiederum zu doppelten Einträgen kommen kann.

        sollte der Fall eintreten (können) dass es zueiner Kennziffer mehrere Datensätze gibt, welche den gleichen Wert in der Spalte 'von' aufweisen, so werden eben mehrere Datensätze geliefert. Falls das unerwünscht ist, so ist die Aufgabenstellung definitiv unterspezifiziert.

        Grüße
          Klaus

      2. hallo vinzenz,

        du hast recht.

        die problemstellung des fragestellers läßt sich mit 'sauberem' sql nicht als einfacher select lösen, da das gewünschte ergebnis einen mix aus gruppierten und ungruppierten spalten darstellt. daher ergibt sich die von ilja genannte lösung, welche zunächst gruppiert die relevanten zeilen ermittelt, und diese dann als bedingung für einen ungruppierten select darstellt.

        das problem entsteht aber nicht durch 'doppelte' max-werte, da max selbst bei doppelten werten immer nur einen max-wert liefert.

        die 'doppelten' zeilen entstehen durch die 'saubere' notation. dies ist die aggregation von 'Bis' und 'Tage'.

        eine ausnahme bildet mysql. es ist in dieser hinsicht sehr tolerant und erlaubt die selektion weiterer spalten, ohne diese zu aggregieren. bei verzicht auf die aggregation von 'Bis' und 'Tage', werden diese als 'nicht aggregiert' geliefert. somit wäre das gewünschte ergebnis erreicht.

        1. yo,

          eine ausnahme bildet mysql. es ist in dieser hinsicht sehr tolerant und erlaubt die selektion weiterer spalten, ohne diese zu aggregieren. bei verzicht auf die aggregation von 'Bis' und 'Tage', werden diese als 'nicht aggregiert' geliefert. somit wäre das gewünschte ergebnis erreicht.

          ein irrglaube, dass mysql toleranter wäre. dies wird deutlich, wenn man sich mal die dokumentation durchlesen würde. mysql erzeugt halt nur kein fehlermeldung, wo eine angebracht wäre. und es würde alles andere als das gewünschte ergebnis erreicht.

          Ilja

          1. probiers aus. dann siehst es.

            toleranz ist auch, die fehler eines anderen nicht anzumeckern.

            1. yo,

              probiers aus. dann siehst es.

              ich gebe dir mal den link, damit du es nachlesen kannst, dass mysql nicht toleranter ist, sondern es nur aus performance-gründen so regelt.

              http://dev.mysql.com/doc/refman/5.1/en/group-by-hidden-fields.html

              dazu das entscheidene zitat: "Do not use this feature if the columns you omit from the GROUP BY part are not unique in the group! You get unpredictable results."

              toleranz ist auch, die fehler eines anderen nicht anzumeckern.

              aha, und ich denke, wer genug selbstvertauen hat, der ist auch tolerant genug, fehler oder angebliche fehler von sich selbst zuzulassen.

              Ilja