我在数据库中有一个包含租户数量的表格,每个租户都列出了每个日期的销售记录。有一个例子,租户在特定日期没有销售,因此没有销售的日期在表格中没有记录,打破了正确的日期顺序。请参阅下面的示例表:
我在sql中使用了这个select查询来显示上面的输出
select tenant, date, sales
from tblSales
where date between '01/01/2015' and '01/05/2014'
我需要的正确输出:根据where子句中选定的日期范围显示完整日期,当租户在特定日期没有记录时,查询应该在该特定租户中添加日期记录并添加销售栏中的空值,如下图所示:
以下是我的开始:
@dateFrom datetime = '02/01/2015',
@dateTo date = '02/05/2015'
declare @MaxNumDays int
declare @Counter int
set @Counter = 0
set @MaxNumDays = DATEDIFF(day, @dateFrom , @dateto) + 1
create table #DSRTdate
(
Date datetime
)
WHILE @Counter < @MaxNumDays
BEGIN
insert into #DSRTdate (Date) values (DATEADD(day,@Counter,@dateFrom ))
SET @Counter += 1
END
我使用上面的代码来获取并在临时表中插入来自使用选择的序列数据,在上面的例子中,它插入02/01 / 2015,02 / 02 / 2015,02 / 03 / 2015,02 / 04/2015,AND 02/05/2015
select tenantcode, date, sales
into #DSRT2
FROM DAILYMOD
where (date BETWEEN @dateFrom and @dateTo )
SELECT *
from #dsrtdate a left join #DSRT2 b
on a.date = b.date
order by b.tenantcode, a.date
然后我使用左连接来显示缺少的日期,但这仅导致一个TENANT,它也使租户名为null。像这样:
任何建议都将受到高度赞赏。
答案 0 :(得分:4)
您可以使用Tally Table。
执行此操作基本上,您使用Tally Table
生成从@startDate
到@endDate
和CROSS JOIN
到DISTINCT Item
的日期序列,以生成所有Date
} - Item
组合。然后,结果将LEFT-JOIN
转到tblSales
以获得所需的输出。
DECLARE
@startDate DATE = '20140101',
@endDate DATE = '20140105';
WITH E1(N) AS(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
,E2(N) AS(SELECT 1 FROM E1 a, E1 b)
,E4(N) AS(SELECT 1 FROM E2 a, E2 b)
,Tally(N) AS(
SELECT TOP (DATEDIFF(DAY, @startDate, @endDate) + 1)
ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
FROM E4
)
,CteAllDates(Item, dt) AS(
SELECT x.Item, DATEADD(DAY, N - 1, @startDate)
FROM Tally
CROSS JOIN(
SELECT DISTINCT Item
FROM tblSales
WHERE [Date] BETWEEN @startDate AND @endDate
) AS x
)
SELECT d.*, ts.Sales
FROM CteAllDates d
LEFT JOIN tblSales ts
ON ts.Item = d.Item
AND ts.Date = d.dt
WHERE
ts.[Date] BETWEEN @startDate AND @endDate
ORDER BY d.Item, d.dt
这是另一种选择。而不是级联CTE
,而是使用sys.columns
生成Tally Table
。:
DECLARE
@startDate DATE = '20140101',
@endDate DATE = '20140105';
WITH Tally(N) AS(
SELECT TOP (DATEDIFF(DAY, @startDate, @endDate) + 1)
ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
FROM sys.columns a, sys.columns b
)
,CteAllDates(Item, dt) AS(
SELECT x.Item, DATEADD(DAY, N - 1, @startDate)
FROM Tally
CROSS JOIN(
SELECT DISTINCT Item
FROM tblSales
WHERE [Date] BETWEEN @startDate AND @endDate
) AS x
)
SELECT d.*, ts.Sales
FROM CteAllDates d
LEFT JOIN tblSales ts
ON ts.Item = d.Item
AND ts.Date = d.dt
WHERE
ts.[Date] BETWEEN @startDate AND @endDate
ORDER BY d.Item, d.dt
<强>结果强>
| Item | dt | Sales |
|---------|------------|--------|
| tenant1 | 2014-01-01 | 100 |
| tenant1 | 2014-01-02 | 100 |
| tenant1 | 2014-01-03 | 100 |
| tenant1 | 2014-01-04 | NULL |
| tenant1 | 2014-01-05 | 100 |
| tenant2 | 2014-01-01 | 100 |
| tenant2 | 2014-01-02 | NULL |
| tenant2 | 2014-01-03 | NULL |
| tenant2 | 2014-01-04 | 100 |
| tenant2 | 2014-01-05 | NULL |
| tenant3 | 2014-01-01 | 100 |
| tenant3 | 2014-01-02 | NULL |
| tenant3 | 2014-01-03 | 100 |
| tenant3 | 2014-01-04 | NULL |
| tenant3 | 2014-01-05 | 100 |