2016-04-09 14 views
0

Ich versuche Folgendes zu erreichen - Ich möchte die Sitzung auf meiner Website pro Kunde gruppiert nach Kalenderwoche sehen. Hier ist die Abfrage ich habe so weit, dies zu erreichen:MYSQL - Nach Wochen gruppieren, während Wochen ohne Werte angezeigt werden

SELECT o.name 
    , s.organization_id 
    , count(s.id) as num_of_sessions 
    , CONCAT(s.created_at, ' - ', s.created_at + INTERVAL 6 DAY) AS week 
    FROM triton.sessions s 
    , triton.organizations o 
where o.id=s.organization_id 
    and s.organization_id in (17,19,20,21,24,25,26,27,29,31,32,33,34,25,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,56,57,58,59,60,62,69,70,72) 
GROUP BY s.organization_id, WEEK(s.created_at) 
ORDER BY o.name, WEEK(s.created_at); 

Das Problem dabei ist, dass Wochen mit dem ein Kunde hat keine Website-Sitzung hat nicht mit einem 0 gemeldet werden - statt in dieser Woche nicht gemeldet . Dies ist ein Problem, da ich die Daten nicht einfach in Excel übernehmen kann und Diagramme für die Sitzungen jedes Kunden erstellen kann.

Um zu versuchen, dieses Problem zu beheben, habe ich eine temporären Wochen Tabelle mit Werten von 1 bis 52 für jede Woche und versuchte der Ansatz in diesem Link vorgeschlagen: Summarise by week, even for empty rows

Die Herausforderung ist, wenn ich eine linke äußere tun Beitreten, ich verliere die Gruppe für Organisationen.

Hier ist ein funktionierendes SQL von Wochen auf nur Gruppe verwendet (vor durch Organisation Gruppe versucht):

select w.weeknum 
    , sess.club 
    , sess.organization_id 
    , count(sess.club) from weeks w 
    left outer 
    join (select o.name as club 
       , s.organization_id 
       , s.created_at 
      from sessions s 
       , organizations o 
      where s.organization_id in (17,19,20,21,24,25,26,27,29,31,32,33,34,25,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,56,57,58,59,60,62,69,70,72) 
      and o.id=s.organization_id 
     ) sess 
    on (w.weeknum = extract(week from sess.created_at)) 
group by w.weeknum 

Der obige Code gibt nur 52 Zeilen (1 für jede Woche), mit der Graf mir geben Wie viele Sitzungen in jeder Woche.

Ich möchte jetzt den oben genannten Code, um die oben genannten aber pro Organisation zu erweitern. Ich sollte 52 * N Zeilen zurückbekommen, wobei N die Anzahl der Organisationen ist. Ich dachte, das wäre so einfach wie das Hinzufügen der Organisation zur groupby-Anweisung, aber es gab nur die Wochen zurück, die Sitzungen hatten (was zu dem Problem führte, das ich von Anfang an hatte). Hier ist die Abfrage:

select w.weeknum 
    , sess.club 
    , sess.organization_id 
    , count(sess.club) 
    from weeks w 
    left outer 
    join (select o.name as club 
       , s.organization_id 
       , s.created_at 
      from sessions s 
       , organizations o 
      where s.organization_id in (17,19,20,21,24,25,26,27,29,31,32,33,34,25,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,56,57,58,59,60,62,69,70,72) 
      and o.id=s.organization_id 
     ) sess 
    on (w.weeknum = extract(week from sess.created_at)) 
group by sess.club, w.weeknum 
order by sess.club 

Hat jemand andere Vorschläge, wo ich meine Ziele erreichen kann? Im Wesentlichen möchte ich für jeden meiner Kunden eine Liste von Sitzungen pro Woche anzeigen (auch wenn sie in einer bestimmten Woche keine Sitzung hatten).

+0

Ich denke, Sie erhalten bessere Antworten, wenn Sie verkürzen deine te xt und formatiere deinen Code –

Antwort

0

Verwenden Sie ein cross join die Zeilen zu bekommen und dann ein left join:

select w.weeknum, s.club, s.organization_id, count(s.club) 
from weeks w cross join 
    organizations o left outer join 
    sessions s 
    on w.weeknum = extract(week from s.created_at) and 
     o.id = s.organization_id 
where o.id in (17,19,20,21,24,25,26,27,29,31,32,33,34,25,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,56,57,58,59,60,62,69,70,72) 
group by w.weeknum, s.club, s.organization_id; 
0

Nehmen Sie einfach Ihre ursprüngliche Abfrage, und wickeln in Pars und als Inline-View verwenden.

Und es sieht so aus, als ob Sie herausgefunden haben, dass Sie eine Zeilenquelle wünschen, die alle Zeilen zurückgibt, die Sie zurückgeben möchten, und dann eine linke Verknüpfung zu Ihrer Inline-Ansicht.

Du hast diesen Teil:

from weeks w 

nur trete ein Kreuz zu all den organization_id Sie zurückkehren möchten.

Es sieht so aus, als ob organisations_id der Primärschlüssel der Organisationstabelle sein könnte. Wenn das der Fall ist, dann würde diese Abfrage das Set zurückkehren Sie wollen:

SELECT v.name 
    , v.organization_id 
    FROM triton.organizations v 
WHERE v.organization_id (17,19,20,21,24,25,26,27,29,31,32,33,34,25,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,56,57,58,59,60,62,69,70,72) 
ORDER BY v.organization_id 

so kann nur ein Kreuz verbindet diesen Satz mit dem weeks rowsource:

SELECT v.name 
     , v.organization_id 
     , w.weeknum 
    FROM triton.organizations v 
    CROSS 
    JOIN weeks w 
    WHERE v.organization_id (17,19,20,21,24,25,26,27,29,31,32,33,34,25,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,56,57,58,59,60,62,69,70,72) 
    ORDER 
     BY v.organization_id 
     , w.weeknum 

Wenn Sie nur eine Teilmenge wollen aus weeks Tabelle, fügen Sie einfach ein Prädikat zu der WHERE Klausel, z

AND w.weeknum BETWEEN 0 AND 104 

Das sollte Sie jeden weeknum für jede orgnisation_id zurückgeben.

Sobald Sie das funktioniert haben, fügen Sie einfach einen "Outer Join" zu Ihrer ursprünglichen Abfrage hinzu, indem Sie der SELECT-Liste einen Ausdruck hinzufügen, der Ihnen einen Wert für weeknum liefert.

Ich bin verwirrt über die Ausdrücke mit created_at. Der für created_at zurückgegebene Wert ist aufgrund der GROUP BY unbestimmt. Wenn Sie die "frühesten" und/oder "neuesten" Werte verwenden möchten, verwenden Sie MIN- und MAX-Aggregate. (created_at Angenommen ist ein Datum, DATETIME- oder Zeitstempel.)

SELECT v.name 
     , v.organization_id 
     , w.weeknum 
     , IFNULL(t.num_of_sessions,0) 
    FROM triton.organizations v 
    CROSS 
    JOIN weeks w 
    LEFT 
    JOIN (
      -- query to get session counts goes here 
     ) t 
     ON t.organization_id = v.organization_id 
    AND t.weeknum   = w.weeknum 
    WHERE v.organization_id (17,19,20,21,24,25,26,27,29,31,32,33,34,25,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,56,57,58,59,60,62,69,70,72) 
    ORDER 
     BY v.organization_id 
     , w.weeknum 

in der äußeren Abfrage Bezug die num_of_sessions Spalt durch die Ansicht zurückgegeben. Die IFNULL-Funktion ist eine bequeme Möglichkeit, eine "fehlende" Anzahl durch eine Null zu ersetzen.

Die Abfrage der „zählt“, um etwas aussehen könnte:

  SELECT s.organization_id AS organization_id 
       , WEEK(s.created_at) AS weeknum 
       , COUNT(s.id)   AS num_of_sessions 
       , MIN(s.created_at) AS min_created_at 
       , MAX(s.created_at) AS max_created_at 
      FROM triton.sessions s 
      WHERE s.organization_id IN (17,19,20,21,24,25,26,27,29,31,32,33,34,25,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,56,57,58,59,60,62,69,70,72) 
      GROUP 
      BY s.organization_id 
       , WEEK(s.created_at) 

Wenn die Absicht dieses Teils der ursprünglichen Abfrage:

CONCAT(s.created_at, ' - ', s.created_at + INTERVAL 6 DAY) AS week 

ist, um das Menü beginnen Datum und Enddatum der Woche, dann generieren Sie das aus den Werten aus der Wochen-Tabelle. (Wenn es eine Organisation gibt, in der es in einer bestimmten Woche nur eine Transaktion gibt, und an einem Donnerstag, wird dieser Ausdruck einen "Donnerstag bis zum folgenden Mittwoch" generieren. Nichts ist falsch daran, aber ich vermute stark, dass das nicht was ist Sie wirklich wollen.

Wenn Sie einen „Sonntag bis samstag“ für jeden WEEKNUM wollen, wäre es besser, dass von dem WEEKNUM Tisch zurückzukehren.

Wenn Sie aktuelle Termine aus Organisation Sitzungen, dann verwenden MIN wollen () und MAX() Werte von created_at, und verketten diese. Diese werden nicht unbedingt "Sonntag bis Samstag", aber jedes Datum zurückgegeben würde "innerhalb" der Woche sein.

Verwandte Themen