我有一张如下表:
Book BookSales Date
BookA $1 2013-03-04
BookB $2 2013-03-04
BookA $3 2013-03-05
... ...
我运行查询 -
select book,booksales,date
from tblBook
where date>='03/03/2013'
and date<='03/05/2013'
and book in ('BookA','BookB')
order by date,book
现在它返回结果如下
BookA $1 2013-03-04
BookB $2 2013-03-04
BookA $3 2013-03-05
但我想要的是返回书b的空结果($ 0),如果该日期不存在,如下所示)。此处,日期2013-03-05中不存在图书b的记录。
BookA $1 2013-03-04
BookB $2 2013-03-04
BookA $3 2013-03-05
BookB $0 2013-03-05 <-- I want to include this record
我怎样才能做到这一点?如果不可能实现这种方式,我还可以考虑采用其他方法吗?
答案 0 :(得分:3)
必须有一种更简单的方法来做到这一点,但这就是我想出来的。使用公用表表达式获取不同的日期列表和不同的书籍列表,然后CROSS JOIN
它们以获得完整的日期和书籍矩阵。一旦你得到了完整的矩阵,你可以OUTER JOIN
你的表,用0代替任何空值。
交叉连接可能会很快变得混乱,但如果它只是一个日期列表和书籍列表,它应该可以正常工作。
;with dates AS
(
select distinct date
from tblBook
), books AS
(
select distinct book
from tblBook
)
select b.book, coalesce(tb.booksales, 0), d.[date]
from dates as d
cross join books as b
left outer join tblBook as tb
on d.[date] = tb.[date]
and b.book = tb.book
where d.[date] >='03/03/2013'
and d.[date] <='03/05/2013'
and b.book in ('BookA','BookB')
order by d.[date], b.[book]
答案 1 :(得分:2)
您可以使用子查询来解决您的问题,该子查询会生成您需要报告的所有不同值。我假设输出应该提供一种方法来跟踪每天每本书的销售情况,即使没有在表格中输入销售交易。这是一个可能的解决方案和输出:
通过构造代表表中所有可能值的sub query
,可以查看查询表中没有物理表示的数据值的请求。
在这种情况下,报告的两个维度是:“book”和“date”。对于书籍销售表中记录的每一天交易,每本书必须有一个总销售额条目。
假设:示例中并不清楚tblBook
是否代表已汇总的销售额,或者是否有针对给定“预订”和“日期”组合的多条记录。 ..就像交易记录的样式一样,记录每笔销售。解决方案查询汇总销售额,以便每天为每本书提供单个记录。
注意:此示例已在MySQL RDBMS上进行了测试。此示例中使用的SQL是ANSI标准,因此它也应该在SQLServer数据库上工作。您可能必须找到与此解决方案中使用的
ifNULL()
函数等效的
SQL代码
SELECT REPORTING_DIMENSIONS.book,
sum(ifNULL(sales_data.bookSales,0)) as totalSales,
REPORTING_DIMENSIONS.date
FROM
(SELECT book_list.book, date_list.date
FROM
(SELECT distinct book
FROM tblBook
) book_list
CROSS JOIN
(SELECT distinct date
FROM tblBook
) date_list
) REPORTING_DIMENSIONS
LEFT JOIN tblBook SALES_DATA
ON REPORTING_DIMENSIONS.book = SALES_DATA.book
AND REPORTING_DIMENSIONS.date = SALES_DATA.date
GROUP BY REPORTING_DIMENSIONS.book,
REPORTING_DIMENSIONS.date
输出:
| BOOK | TOTALSALES | DATE |
|-------|------------|------------------------------|
| BookA | 2 | March, 04 2013 00:00:00+0000 |
| BookA | 6 | March, 05 2013 00:00:00+0000 |
| BookB | 4 | March, 04 2013 00:00:00+0000 |
| BookB | 0 | March, 05 2013 00:00:00+0000 |
BookB在2013-03-15的零值实际上是一个NULL值。当进行OUTER(即LEFT)连接时,连接值不匹配,返回null。
唯一的奇特步骤是CROSS JOIN
指定。也称为CARTESIAN PRODUCT
,这会为现有表格中记录的每个可能的“书籍”和“日期”组合生成记录。
别名为REPORTING DIMENSIONS
的子查询是查询的固定动态功能。它允许查询在新书或日期添加到其范围时调整其输出。
其他注意事项:
在报告查询范围内包含的一个,所有或许多日历日内,可能没有任何产品销售。这将再次影响原始报表查询的输出,因为结果输出中将存在漏洞。
可以通过仅为日期值创建固定维度表来解决此问题。在销售数据范围之前和之后的几年内,预先填写每个离散日历日的记录。带有循环插入操作的简单T / SQL块可以轻松填充此表。一旦填充完毕,就不太可能需要触摸它。
答案 2 :(得分:1)
如果你有这个
Book BookSales Date
BookA $1 2013-03-04
BookB $2 2013-03-04
BookA $3 2013-03-06
并希望
BookA $1 2013-03-04
BookB $2 2013-03-04
BookA $0 2013-03-05
BookB $0 2013-03-05
BookA $3 2013-03-06
BookB $0 2013-03-06
杰夫罗森伯格的答案被盗t-sql get all dates between 2 dates
;WITH dates AS
(
SELECT CAST('2013-03-04' AS DATETIME) AS [date]
UNION ALL
SELECT DATEADD(dd, 1, [date])
FROM dates s
WHERE DATEADD(dd, 1, [date]) <= CAST('2013-03-06' AS DATETIME)), books AS
(
select distinct book
from tblBooks
)
select b.book, coalesce(tb.booksales, 0), d.[date]
from dates as d
cross join books as b
left outer join tblBooks as tb
on d.[date] = tb.[date]
and b.book = tb.book
如果你需要聚合
...
SELECT b.Book, COALESCE(SUM(tb.BookSales), 0), d.[Date]
FROM Dates d
CROSS JOIN Books b
LEFT JOIN tblBooks tb ON d.[Date] = tb.Date
AND b.Book = tb.Book
GROUP BY b.Book, d.[Date]