2016-04-09 10 views
0

私は以下のことを達成しようとしています - 顧客ごとのセッションをカレンダー週ごとにグループ化したいと思っています。ここで私は、これを達成するために、これまで持っているクエリは次のとおりです。MYSQL - 値のない週を表示しながら週ごとにグループ化する

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); 

これで問題は、顧客がWebサイトのセッションを持っていなかったところで週は0と報告されていないということです - 代わりにその週は報告されていません。これは、データをExcelに簡単に取り込むことができず、顧客のセッションごとにグラフを作成できないため、問題です。この問題を解決しようとする

、私は毎週番号の1から52の値で一時週間テーブルを作成し、アプローチは、このリンクで提案しようとしました:私は左の外側を行う際Summarise by week, even for empty rows

課題であります私は団体のためにグループを失う。ここで

は(組織によってグループにしようとする前に)週間だけのグループに使用され、作業SQLです:

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 

上記のコードだけカウントが私に与えて、52行(各週1)を返します。各週のセッション数

上記のコードを組織単位で拡張したいと考えています。私は52 * Nの行を返すべきです。ここで、Nは組織の数です。私はこれがgroupbyのステートメントに組織を追加するのと同じくらい簡単だと思っていましたが、それからsesssionsを持つ週が戻ってきました(最初から問題がありました)。クエリは次のとおりです。

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 

私の目標を達成するための他の提案はありますか?基本的に私の顧客の皆様には、週ごとのセッションリストを見たいと思っています(特定の週にセッションがなかったとしても)。

+0

私はあなたが短く場合は、より良い回答を得るだ​​ろうと思いますあなたのテコードをフォーマットしてフォーマットする –

答えて

0

使用cross joinはその後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

ちょうどあなたの元のクエリを取り、括弧でラップし、インライン・ビューとして使用します。

そして、返されるすべての行を返す行ソースと、インラインビューへの左結合が必要なことがわかったようです。

あなたはこの部分を得た:

from weeks w 

はちょうどクロスはあなたが戻りたいORGANIZATION_IDのすべてに参加します。

organization_idが組織テーブルの主キーである可能性があります。あなただけのサブセットを使用する場合は

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 

:ので、ちょうどクロスweeks値集合ソースと、そのセットのジョインん

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 

:そのような場合、このクエリは、あなたが望むセットを返しますweeksテーブル、ちょうど述語をWHERE句に追加してください。

AND w.weeknum BETWEEN 0 AND 104 

これは、すべてのorganization_idに対して毎週あなたを返す必要があります。

あなたが働いていることを得れば、今ちょうど、あなたの元のクエリに「外部結合」を追加あなたWEEKNUMすると一致する値を取得するSELECTリストに式を追加します。

私はcreated_atを含む式について困惑しています。 created_atのために返された値が原因GROUP BYに、不確定です。あなたが「早い」および/または「最新」の値をしたい場合は、MINとMAXの集計を使用します。 (created_atと仮定するとDATE、DATETIMEまたはTIMESTAMPである。)

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 

外側のクエリでは、ビューによって返さnum_of_sessions列を参照します。 IFNULL関数は、 "欠落した"カウントを0に置き換える便利な方法です。

「カウント」を取得するクエリ可能性が何かのように:

  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) 

元のクエリのこの部分の目的の場合:

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

を表示することです開始日付と終了日を入力し、週表の値から生成します。 (そこに1つのトランザクションのみが特定の週にあります組織はだし、それは木曜日になら、その式は、「水曜日次へ木曜日」を生成しようとしている。それを行うと間違って何もないが、私は強くそれが何でない疑いがありますあなたが本当にしたい。

あなたは、各WEEKNUMについて「土曜日に日曜日を」したい場合、WEEKNUMテーブルからということを返す方が良いでしょう。

あなたは、組織のセッションからの実際の日付にしたい場合は、MINを使用します( )とのcreated_atのMAX()値、およびそれらを連結します。それらは必ずしも「土曜日に日曜日」ではありませんが、任意の日付は一週間「以内」になり戻った。

関連する問題