简体   繁体   English

一个桶不存在数据时,如何选择桶中的SQL数据?

[英]How do I select SQL data in buckets when data doesn't exist for one bucket?

I'm trying to get a complete set of buckets for a given dataset, even if no records exist for some buckets .我正在尝试为给定的数据集获取一组完整的存储桶,即使某些存储桶不存在记录

For example, I want to display totals by day of week, with zero total for days with no records.例如,我想按星期几显示总计,没有记录的天数总计为零。

SELECT
WEEKDAY(transaction_date) AS day_of_week,
SUM(sales) AS total_sales
FROM table1
GROUP BY day_of_week

If I have sales every day, I'll get 7 rows in my result representing total sales on days 0-6.如果我每天都有销售,我将在结果中得到 7 行,代表第 0-6 天的总销售额。

If I don't have sales on Day 2, I get no result for Day 2.如果我在第 2 天没有销售,那么第 2 天就没有结果。

What's the most efficient way to force a zero value for day 2?强制第 2 天为零值的最有效方法是什么?

Should I join to a temporary table or array of defined buckets?我应该加入临时表还是已定义存储桶的数组? ['0','1','2','3','4','5','6'] ['0','1','2','3','4','5','6']

Or is it better to insert zeros outside of MySQL, after I've done the query?还是在我完成查询后在 MySQL 之外插入零更好?

I am using MySQL, but this is a general SQL question.我正在使用 MySQL,但这是一个通用的 SQL 问题。

Basically you want the answer to be 0 when the data is actually null for that bucket, therefore you want the max(null, 0).基本上,当该存储桶的数据实际上为空时,您希望答案为 0,因此您需要 max(null, 0)。 A max function wouldn't natively work with NULL in this way, however, you can use COALESCE to force it: max 函数本身不会以这种方式与 NULL 一起使用,但是,您可以使用 COALESCE 强制它:

COALESCE(MAX(SUM(sales)),0)

as suggested by this answer正如这个答案所建议的

First off you need a calendar table;首先你需要一个日历表; something like this or this .这样这样的东西。 Or create calendar subset on the fly.或者动态创建日历子集。 I am not sure of the mySQL syntax, but here is what it would look like in SQL Server.我不确定 mySQL 语法,但这里是它在 SQL Server 中的样子。

DECLARE
    @FromDate DATE
  , @ToDate   DATE

-- set these variables to appropriate values
SET @FromDate = '2020-03-01';
SET @ToDate = '2020-03-31';

;WITH cteCalendar (MyDate) AS
(
    SELECT CONVERT(DATE, @FromDate) AS MyDate
    UNION ALL
    SELECT DATEADD(DAY, 1, MyDate)
    FROM   cteCalendar
    WHERE  DATEADD(DAY, 1, MyDate) <= @ToDate
)
SELECT WEEKDAY(cte.MyDate) AS day_of_week,
SUM(sales) AS total_sales
FROM cteCalendar cte
LEFT JOIN table1 t1 ON cte.MyDate = t1.transaction_date
GROUP BY day_of_week

In MySQL, you could simply use a derived table of numbers from 1 to 7 , left join it with the table, then aggregate:在 MySQL 中,您可以简单地使用从17的数字派生表, left join其与表left join ,然后聚合:

select d.day_of_week, sum(sales) AS total_sales
from (
    select 1 day_of_week union all select 2 union all select 3 union all select 4
    union all select 5 union all select 6 union all select 7
) d
left join table1 t1 on weekday(t1.transaction_date) = d.day_of_week
group by day_of_week

Very recent versions have the values(row...) syntax, which shorten the query:最新版本具有values(row...)语法,它缩短了查询:

select d.day_of_week, sum(sales) AS total_sales
from (values row(1), row(2), row(3), row(4), row(5), row(6), row(7)) d(day_of_week)
left join table1 t1 on weekday(t1.transaction_date) = d.day_of_week
group by day_of_week

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM