none
SQL Abfrage für mehrfach vorkommende Werte in 2 Spalten RRS feed

  • Frage

  • Auf Anregung eines Forenmitgliedes möchte ich hiermit einen neuen Thread für mein Problem eröffnen.

    Mein Problem ist, alle Vorkommen von zwei verschiedenen Produktpaketen Pn in unterschiedlichen Filialen Fn zu zählen, genau dann wenn 2 Produktpakete in einer Filiale einmal als ProduktPaket1 und dann als ProduktPaket2 vorhanden sind. Das wird bei uns TWIN genannt.

    Die nachfolgende Tabelle zeigt die Ausgangssituation:

    Declare @myTab as Table(Filiale char(2), ProduktPaket1 char(2), ProduktPaket2 char(2));

    Insert into @myTab(Filiale, ProduktPaket1, ProduktPaket2)
    values('F1', 'P1', 'P2');
    Insert into @myTab(Filiale, ProduktPaket1, ProduktPaket2)
    values('F1', 'P2', 'P1');
    Insert into @myTab(Filiale, ProduktPaket1, ProduktPaket2)
    values('F2', 'P1', 'P2');
    Insert into @myTab(Filiale, ProduktPaket1, ProduktPaket2)
    values('F1', 'P2', 'P1');
    Insert into @myTab(Filiale, ProduktPaket1, ProduktPaket2)
    values('F2', 'P1', '');
    Insert into @myTab(Filiale, ProduktPaket1, ProduktPaket2)
    values('F2', 'P1', 'P2');
    Insert into @myTab(Filiale, ProduktPaket1, ProduktPaket2)
    values('F3', 'P3', 'P1');
    Insert into @myTab(Filiale, ProduktPaket1, ProduktPaket2)
    values('F3', 'P1', '');
    Insert into @myTab(Filiale, ProduktPaket1, ProduktPaket2)
    values('F3', 'P1', 'P3');
    Insert into @myTab(Filiale, ProduktPaket1, ProduktPaket2)
    values('F3', 'P2', 'P1');
    Insert into @myTab(Filiale, ProduktPaket1, ProduktPaket2)
    values('F3', 'P1', 'P2');

           

    Das Ergebnis soll wie rechts gezeigt aussehen.

    Ich habe mir schon die Zähne daran ausgebissen, aber bin zu keiner Lösung gekommen.

    Vielleicht findet sich hier ja jemand, der mir auf die Sprünge helfen kann.

    Im Voraus schon mal vielen Dank für evtl. Überlegungen.

    Gruß Jürgen

    Mittwoch, 17. Oktober 2012 18:55

Antworten

  • Den letzten Teil kann man natürlich auch noch etwas kürzen:

    Select Twin, ProduktPaket1, ProduktPaket2,
    sum(case when Filiale = 'F1' then 1 else 0 end) as F1,
    sum(case when Filiale = 'F2' then 1 else 0 end) as F2,
    sum(case when Filiale = 'F3' then 1 else 0 end) as F3,
    count(distinct Filiale) as Anzahl_Filialen, count(*) as Anzahl_Kombi
    from cte
    group by Twin, ProduktPaket1, ProduktPaket2
    order by Twin;

    Einen schönen Tag noch,
    Christoph
    --
    Microsoft SQL Server MVP
    www.insidesql.org/blogs/cmu

    • Als Antwort markiert Jürgen Sch Freitag, 19. Oktober 2012 00:06
    Donnerstag, 18. Oktober 2012 07:20
    Beantworter

Alle Antworten

  • Hallo Jürgen,

    ich würde es so machen:

    SELECT     'P1_P2' AS Twin, COUNT(DISTINCT Filiale) AS AnzahlFilialen, COUNT(Filiale) AS AnzahlTwins
    FROM         (SELECT     Filiale, ProduktPaket1, ProduktPaket2
    FROM          test.dbo.tbl_Twins
    WHERE      (ProduktPaket1 = N'P1') AND (ProduktPaket2 = N'P2') OR
    (ProduktPaket1 = N'P2') AND (ProduktPaket2 = N'P1')) AS Twin1
    UNION ALL
    SELECT     'P1_P3' AS Twin, COUNT(DISTINCT Filiale) AS AnzahlFilialen, COUNT(Filiale) AS AnzahlTwins
    FROM         (SELECT     Filiale, ProduktPaket1, ProduktPaket2
    FROM          test.dbo.tbl_Twins
    WHERE      (ProduktPaket1 = N'P1') AND (ProduktPaket2 = N'P3') OR
    (ProduktPaket1 = N'P3') AND (ProduktPaket2 = N'P1')) AS Twin2    


    Mittwoch, 17. Oktober 2012 21:38
  • Hallo Jürgen, versuch mal folgendes:

    Select a.Filiale,
    case when a.ProduktPaket1 < a.ProduktPaket2 then a.ProduktPaket1 else
    a.ProduktPaket2 end    + '_' +
    case when a.ProduktPaket1 >= a.ProduktPaket2 then a.ProduktPaket1 else
    a.ProduktPaket2 end as Twin,
    case when a.ProduktPaket1 < a.ProduktPaket2 then a.ProduktPaket1 else
    a.ProduktPaket2 end    as ProduktPaket1,
    case when a.ProduktPaket1 >= a.ProduktPaket2 then a.ProduktPaket1 else
    a.ProduktPaket2 end as ProduktPaket2
    from @myTab a
    where a.ProduktPaket1 is not null
    and a.ProduktPaket2 is not null
    and exists(Select *
    from @myTab b where    a.ProduktPaket2 = b.ProduktPaket1 and a.Filiale =
    b.Filiale)
    order by Twin, Filiale;
    
    with cte as
    (
    Select a.Filiale,
    case when a.ProduktPaket1 < a.ProduktPaket2 then a.ProduktPaket1 else
    a.ProduktPaket2 end    + '_' +
    case when a.ProduktPaket1 >= a.ProduktPaket2 then a.ProduktPaket1 else
    a.ProduktPaket2 end as Twin,
    case when a.ProduktPaket1 < a.ProduktPaket2 then a.ProduktPaket1 else
    a.ProduktPaket2 end    as ProduktPaket1,
    case when a.ProduktPaket1 >= a.ProduktPaket2 then a.ProduktPaket1 else
    a.ProduktPaket2 end as ProduktPaket2
    from @myTab a
    where a.ProduktPaket1 is not null
    and a.ProduktPaket2 is not null
    and exists(Select *
    from @myTab b where    a.ProduktPaket2 = b.ProduktPaket1 and a.Filiale =
    b.Filiale)
    )
    Select Twin, min(ProduktPaket1) as ProduktPaket1, min(ProduktPaket2) as
    ProduktPaket2,
    sum(case when Filiale = 'F1' then 1 else 0 end) as F1,
    sum(case when Filiale = 'F2' then 1 else 0 end) as F2,
    sum(case when Filiale = 'F3' then 1 else 0 end) as F3,
    count(distinct Filiale) as Anzahl_Filialen, count(*) as Anzahl_Kombi
    from cte
    group by Twin
    order by Twin;

    Ich habe die Abfrage etwas gedreht, suche also (where exists...) nach den Sätzen, die als ProduktPaket1 das Element haben, was im äußeren Select in ProduktPaket2 ist.
    Dadurch habe ich im äußeren Select immer beide ProduktPakete gefüllt und kann daraus den Twin zusammen bauen.
    Dass bei einem Twin die Produktpakete aufsteigend sortiert werden sollen, habe ich mir mal aus der Grafik erschlossen, den sonst hätten wir ja nur zwei Twins bei Filiale 1 mit P2_P1 und der Satz mit P1_P2 würde unter den Tisch fallen.

    Einen schönen Tag noch,
    Christoph
    --
    Microsoft SQL Server MVP
    www.insidesql.org/blogs/cmu

    Donnerstag, 18. Oktober 2012 07:16
    Beantworter
  • Den letzten Teil kann man natürlich auch noch etwas kürzen:

    Select Twin, ProduktPaket1, ProduktPaket2,
    sum(case when Filiale = 'F1' then 1 else 0 end) as F1,
    sum(case when Filiale = 'F2' then 1 else 0 end) as F2,
    sum(case when Filiale = 'F3' then 1 else 0 end) as F3,
    count(distinct Filiale) as Anzahl_Filialen, count(*) as Anzahl_Kombi
    from cte
    group by Twin, ProduktPaket1, ProduktPaket2
    order by Twin;

    Einen schönen Tag noch,
    Christoph
    --
    Microsoft SQL Server MVP
    www.insidesql.org/blogs/cmu

    • Als Antwort markiert Jürgen Sch Freitag, 19. Oktober 2012 00:06
    Donnerstag, 18. Oktober 2012 07:20
    Beantworter
  • Hallo Jürgen,

    ich würde es so machen:

    SELECT     'P1_P2' AS Twin, COUNT(DISTINCT Filiale) AS AnzahlFilialen, COUNT(Filiale) AS AnzahlTwins
    FROM         (SELECT     Filiale, ProduktPaket1, ProduktPaket2
    FROM          test.dbo.tbl_Twins
    WHERE      (ProduktPaket1 = N'P1') AND (ProduktPaket2 = N'P2') OR
    (ProduktPaket1 = N'P2') AND (ProduktPaket2 = N'P1')) AS Twin1
    UNION ALL
    SELECT     'P1_P3' AS Twin, COUNT(DISTINCT Filiale) AS AnzahlFilialen, COUNT(Filiale) AS AnzahlTwins
    FROM         (SELECT     Filiale, ProduktPaket1, ProduktPaket2
    FROM          test.dbo.tbl_Twins
    WHERE      (ProduktPaket1 = N'P1') AND (ProduktPaket2 = N'P3') OR
    (ProduktPaket1 = N'P3') AND (ProduktPaket2 = N'P1')) AS Twin2    


    Hallo Stephan,

    danke erst einmal für deinen Lösungsvorschlag. Er funktioniert auch in so weit, dass die beiden Ergebnisspalten richtig generiert werden:

    Twin AnzahlFilialen AnzahlTwins
    P1_P2 2 4
    P1_P3 1 1

    Allerdings fehlen die Zwischenergebnisse der Twins in den einzelnen Filialen. Außerdem setzt du die vorgegebenen Twins P1_P2 und P1_P3 in deiner Abfrage als gegeben voraus, was ich jedoch beim Start noch gar nicht weiß, d.h. diese sind dynamisch.

    Gruß Jürgen

    Donnerstag, 18. Oktober 2012 15:04
  • Hallo Christoph,

    dein Vorschlag trifft wieder den Nagel auf den Kopf und liefert das gewünschte Ergebnis. Super!!!

    Jetzt muss ich die Abfrage nur noch so umbauen, dass sie in bezug auf die Filialen dynamisch ist, weil die Namen der Filialen variabel sein können, diese bei deiner Lösung für die Summenbildung jedoch fest vorgegeben sind, oder hast du da noch schnell eine Anpassung parat?

    Im Übrigen habe ich im November einen 2 wöchigen SQL-Lehrgang, wo ich hoffe, dass ich dann noch besser klar komme. :-)

    Schönen Gruß und vielen Dank für deine Bemühungen.

    Jürgen

    Donnerstag, 18. Oktober 2012 15:11
  • Allerdings fehlen die Zwischenergebnisse der Twins in den einzelnen Filialen. Außerdem setzt du die vorgegebenen Twins P1_P2 und P1_P3 in deiner Abfrage als gegeben voraus, was ich jedoch beim Start noch gar nicht weiß, d.h. diese sind dynamisch.

    Hallo Jürgen,

    ich hatte deine Anforderungen anscheinend nicht richtig verstanden. Was solls, ich hatte dennoch meinen Spaß. ;-)

    Da du schon eine Lösung hast, brauche ich mir ja keine weiteren Gedanken zu machen.

    Gruß

    Stephan

    Donnerstag, 18. Oktober 2012 17:23
  • Danke an Christoph und auch danke an Stephan.

    Ich habe alles gut umsetzen können, auch dynamisch! Es funzt, wie so schön gebloggt wird.

    Wen die dynamische Anpassung interessiert, der kann sich ja noch mal melden.

    Alles Gute

    Jürgen

    Freitag, 19. Oktober 2012 00:06