12603


一日の売上を一月分表示したいです。

売上テーブルには、  
日付と時間、その売上額が保存されているものとします。

[code]

    売上 日付
    --------------------------
    1000   2015-01-04 15:00:22
    1300   2015-01-05 15:00:22
    1200   2015-01-10 10:14:52
     400   2015-01-11 09:02:01
    1200   2015-01-11 11:04:22
    5000   2015-01-20 15:50:22
    1200   2015-01-20 19:42:19
    5000   2015-01-21 14:00:22
    
[/code]

以下のSQLを実行するとその日付ごとの売り上げの合計値が求められるはずですが、

[code]

    SELECT 日付 , SUM(売上額) FROM 売上
    WHERE 日付　BETWEEN　'2015-01-01' AND '2015-01-31'
    GROUP BY 日付
    
[/code]

結果

[code]

    売上 日付
    --------------------------
    1000   2015-01-04
    1300   2015-01-05
    1200   2015-01-10
    1600   2015-01-11
    6200   2015-01-20
    5000   2015-01-21
    
[/code]

と表示されるはずですが、

もし売り上げが無い日（例えばここに2015-01-01の日付で売上を0として）表示するにはどうすれば良いのでしょうか


CC BY-SA 3.0
2015-07-23T04:48:25.090
12597
2023-08-14T05:56:40.977
10646
question
mysql sql
SQLで無いデータを表示させたい


MySQLを今すぐ使える環境が無いので試せないのですが……

集計したい期間について毎日の売り上げをゼロとしたテンポラリのテーブルを作成し、  
それをUNIONでくっつけて集計すれば同等のことはできると思います。

テンポラリテーブルを動的に作成するか、事前に用意しておくかは作り方次第かと。


CC BY-SA 3.0
2015-07-23T05:49:08.110
12599
2015-07-23T05:49:08.110
10538
12597
answer


表示したい日付をすべて用意して、それに対して売上を LEFT JOIN すると、表示したい日付がすべて出現します  
売上のなかった日の売上の値は NULL になってしまいますので、NULL を 0 に変換してあげます

postgresql なら、generate_series関数で日付の連続をその場で生成することができ、便利です  
mysqlでも同様のことができると思います

<http://sqlfiddle.com/#!15/9eecb7db59d16c80417c72d1e1f4fbf1/1970>

[code]

    WITH 売上 AS (
    SELECT * FROM (
    VALUES
        (1000,'2015-01-04 15:00:22'::timestamp),
        (1300,'2015-01-05 15:00:22'::timestamp),
        (1200,'2015-01-10 10:14:52'::timestamp),
        (400,'2015-01-11 09:02:01'::timestamp),
        (1200,'2015-01-11 11:04:22'::timestamp),
        (5000,'2015-01-20 15:50:22'::timestamp),
        (1200,'2015-01-20 19:42:19'::timestamp),
        (5000,'2015-01-21 14:00:22'::timestamp)
    ) AS T(売上額, 日付)
    )
    SELECT
        COALESCE(売上.売上額, 0) AS 売上額,
        COALESCE(売上.日付, dateSeq) AS 日付
    FROM (
        SELECT
            *
        FROM
            generate_series(
                '2015-01-01'::DATE,
                '2015-12-31',
                '1 day'
            )
    ) AS T(dateSeq)
    LEFT JOIN
        売上 ON (売上.日付::date = dateSeq::date)
    ORDER BY
        dateSeq, 日付
    ;
    
[/code]


CC BY-SA 3.0
2015-07-23T06:04:28.383
12603
2015-07-23T06:04:28.383
9796
12597
answer


私なら集計したい期間の実テーブルを作成し、対象となるテーブルを Left outer join で結合します。


CC BY-SA 3.0
2015-08-28T16:16:10.153
14976
2015-08-28T16:16:10.153
10937
12597
answer


MySQLユーザーのために追記しておきます。

[code]

    CREATE TABLE source (cat int, price int, date timestamp);
    INSERT INTO source (cat, price, date)
    VALUES
        (1, 1000,'2022-01-04 15:00:22'),
        (2, 1300,'2022-02-05 15:00:22'),
        (2, 1200,'2022-03-10 10:14:52'),
        (1, 400,'2022-04-11 09:02:01'),
        (1, 1200,'2022-05-11 11:04:22'),
        (2, 5000,'2022-06-20 15:50:22'),
        (1, 1200,'2022-07-20 19:42:19'),
        (2, 5000,'2022-08-21 14:00:22');
    
    SELECT
        all_months.p_month,
        IFNULL(SUM(source.price), 0) AS t_price
    FROM
        (
            SELECT DISTINCT
                date_format(date, '%Y-%m') AS p_month
            FROM
                source
        ) all_months
        
    LEFT JOIN source ON all_months.p_month = date_format(source.date, '%Y-%m') AND source.cat = 1
    
    GROUP BY
        all_months.p_month;
    
[/code]

<http://sqlfiddle.com/#!9/7485ac/1>


CC BY-SA 4.0
2023-08-14T05:56:40.977
95936
2023-08-14T05:56:40.977
59467
12597
answer