Announcement

Collapse
No announcement yet.

Wie kann man nur den ersten Wert innerhalb einer Gruppe auswählen?

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Wie kann man nur den ersten Wert innerhalb einer Gruppe auswählen?

    Ich habe eine Auftragstabelle mit x Aufträgen pro Tag.
    Wie kann ich für einen Tag nur jeweils den ersten Auftrag ermitteln (Group by mit Einschränkung)?

    Ich habe bisher folgenden Select:

    select fa.Datum, fa.Kdnr
    from auftrag fa
    where fa.datum > '12-oct-2012'
    group by fa.Datum, fa.kdnr
    order by fa.Datum desc;

    Ergebnis aktuell Ist-Zustand mit diesem Select:

    Datum Kdnr
    15.10.12 1000
    15.10.12 1001
    15.10.12 1002
    14.10.12 2000
    13.10.12 3000
    13.10.12 3001

    Soll-Ergebnis sollte aber sein? :

    Datum Kdnr
    15.10.12 1000
    14.10.12 2000
    13.10.12 3000

  • #2
    Erstmal ist die Frage, was ist der erste Eintrag? Die kleinste Kundennummer?
    Dann ginge es so:
    [HIGHLIGHT=SQL]
    select trunc(fa.Datum) as Datum, min(fa.Kdnr) as Kdnr
    from auftrag fa
    where trunc(fa.datum) > '12-oct-2012'
    group by trunc(fa.Datum)
    order by trunc(fa.Datum) desc;
    [/HIGHLIGHT]
    Das Trunc ist nur sicherheitshalber drin, falls eine Uhrzeit das Ergebnis verändern würde. Kann auch rausbleiben bei passenden Contstraints.
    Gruß, defo

    Comment


    • #3
      Ach da hat @defo schon geantwortet...
      Zur Ergänzung nur, wenn es noch mehr Spalten gibt, die "passend" angezeigt werden, dann könnte man KEEP verwenden:
      Code:
      WITH data AS (
        SELECT to_date('15.10.12','DD.MM.YY') datum, 1000 kdnr, 3 aufnr FROM dual UNION ALL
        SELECT to_date('15.10.12','DD.MM.YY')      , 1001     , 2       FROM dual UNION ALL
        SELECT to_date('15.10.12','DD.MM.YY')      , 1002     , 1       FROM dual UNION ALL
        SELECT to_date('14.10.12','DD.MM.YY')      , 2000     , 1       FROM dual UNION ALL
        SELECT to_date('13.10.12','DD.MM.YY')      , 3000     , 2       FROM dual UNION ALL
        SELECT to_date('13.10.12','DD.MM.YY')      , 3001     , 1       FROM dual)
      SELECT datum, min(kdnr) kdnr,
             min(aufnr) aufnr_err,  
             min (aufnr) KEEP (DENSE_RANK FIRST ORDER BY kdnr) aufnr_ok   
        FROM data
       GROUP BY datum; 
      
      datum           kdnr    aufnr_err aufnr_ok
      -------------------------------------------------------
      13.10.2012	3000	1	   2
      14.10.2012	2000	1	   1
      15.10.2012	1000	1	   3

      Comment


      • #4
        Super, das hilft mir schon mal sehr gut weiter.
        Gibt es auch eine Möglichkeit eine bestimmte Anzahl für jede Gruppe zu ermitteln?
        Also z. B. nicht nur die erste (hier die kleinste) Kundennummer eines Tages, sondern z. B. die ersten 2 kleinsten Kundennummern eines Tages auszugeben. (Quasi einen Teilauszug für jeden Tag)

        Comment


        • #5
          Originally posted by maxbreak View Post
          Super, das hilft mir schon mal sehr gut weiter.
          Gibt es auch eine Möglichkeit eine bestimmte Anzahl für jede Gruppe zu ermitteln?
          Also z. B. nicht nur die erste (hier die kleinste) Kundennummer eines Tages, sondern z. B. die ersten 2 kleinsten Kundennummern eines Tages auszugeben. (Quasi einen Teilauszug für jeden Tag)
          Ja, mit window-functions, z.B. row_number() innerhalb jeder Gruppe zählen und dann auf die row_number - Spalte filtern. Ich könnte es Dir mit PG zeigen, kann Oraggle aber auch.

          Andreas

          Comment


          • #6
            Eine kleine Ergänzung im Beispiel gibt mit analytischen Funktionen die sortierte Reihenfolge aus:
            Code:
            WITH data AS (
              SELECT to_date('15.10.12','DD.MM.YY') datum, 1000 kdnr, 3 aufnr FROM dual UNION ALL
              SELECT to_date('15.10.12','DD.MM.YY')      , 1001     , 2       FROM dual UNION ALL
              SELECT to_date('15.10.12','DD.MM.YY')      , 1002     , 1       FROM dual UNION ALL
              SELECT to_date('14.10.12','DD.MM.YY')      , 2000     , 1       FROM dual UNION ALL
              SELECT to_date('13.10.12','DD.MM.YY')      , 3000     , 2       FROM dual UNION ALL
              SELECT to_date('13.10.12','DD.MM.YY')      , 3001     , 1       FROM dual)
            SELECT datum, 
                   row_number () OVER (PARTITION BY datum ORDER BY kdnr) lfdnr,
                   kdnr, aufnr 
              FROM data;
            
            datum           lfdnr   kdnr    aufnr
            -------------------------------------------
            13.10.2012	1	3000	2
            13.10.2012	2	3001	1
            14.10.2012	1	2000	1
            15.10.2012	1	1000	3
            15.10.2012	2	1001	2
            15.10.2012	3	1002	1
            Mit einem äußeren SELECT könnten z.B. dann alle Sätze zwischen 1 und n, d.h. die ersten n Sätze ausgefiltert werden.

            Comment


            • #7
              Prima, funktioniert!
              Hier die beiden Probleme kombiniert: Es werden jeweils die ersten drei Sätze jeder Gruppe werden angezeigt. (Mit gruppeninterner Nummerierung)

              Select innersel.datum, innersel.kdnr, innersel.aufnr, innersel.lfdnr
              From
              (WITH data AS (
              SELECT to_date('15.10.12','DD.MM.YY') datum, 1000 kdnr, 555 aufnr FROM dual UNION ALL
              SELECT to_date('15.10.12','DD.MM.YY') , 1001 , 2 FROM dual UNION ALL
              SELECT to_date('15.10.12','DD.MM.YY') , 1002 , 1 FROM dual UNION ALL
              SELECT to_date('15.10.12','DD.MM.YY') , 900 , 444 FROM dual UNION ALL
              SELECT to_date('14.10.12','DD.MM.YY') , 2000 , 1 FROM dual UNION ALL
              SELECT to_date('13.10.12','DD.MM.YY') , 100 , 12 FROM dual UNION ALL
              SELECT to_date('13.10.12','DD.MM.YY') , 200 , 34 FROM dual UNION ALL
              SELECT to_date('13.10.12','DD.MM.YY') , 3000 , 45 FROM dual UNION ALL
              SELECT to_date('13.10.12','DD.MM.YY') , 3001 , 67 FROM dual)
              SELECT datum,
              kdnr,
              aufnr,
              row_number () over (Partition by datum order by kdnr desc) lfdnr
              FROM data
              order by datum asc, kdnr desc) innersel
              where innersel.lfdnr < 4;

              DATUM KDNR AUFNR LFDNR
              13.10.12 3001 67 1
              13.10.12 3000 45 2
              13.10.12 200 34 3
              14.10.12 2000 1 1
              15.10.12 1002 1 1
              15.10.12 1001 2 2
              15.10.12 1000 555 3

              Comment

              Working...
              X