SQL Server查询 - 使用Tally表

时间:2015-04-29 02:39:45

标签: sql asp.net sql-server crystal-reports

我在数据库中有一个包含租户数量的表格,每个租户都列出了每个日期的销售记录。有一个例子,租户在特定日期没有销售,因此没有销售的日期在表格中没有记录,打破了正确的日期顺序。请参阅下面的示例表:

enter image description here

我在sql中使用了这个select查询来显示上面的输出

select tenant, date, sales
from tblSales
where date between '01/01/2015' and '01/05/2014'

我需要的正确输出:根据where子句中选定的日期范围显示完整日期,当租户在特定日期没有记录时,查询应该在该特定租户中添加日期记录并添加销售栏中的空值,如下图所示:

enter image description here

  1. 作为我的初始解决方案,我想到了创建一个临时表,根据所选的日期范围插入一个日期序列,并使用它来与实际表格保持联接。
  2. 以下是我的开始:

    @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。像这样:

    enter image description here

    任何建议都将受到高度赞赏。

1 个答案:

答案 0 :(得分:4)

您可以使用Tally Table

执行此操作

基本上,您使用Tally Table生成从@startDate@endDateCROSS JOINDISTINCT Item的日期序列,以生成所有Date } - Item组合。然后,结果将LEFT-JOIN转到tblSales以获得所需的输出。

SQL Fiddle

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 |