如何在PIVOT SQL查询上的日期过滤器之间添加

时间:2019-02-20 08:36:16

标签: sql sql-server tsql

我已存储记录了类型和日期的数据。我想获取每个日期每种类型的总数。我有一个具有以下模式的表:

Id |   Type   |      Date_and_Time      |
----------------------------------------
1  |   Bags   | 2019-01-01 17:39:34.620 |
2  |   Shoes  | 2019-01-02 17:39:34.620 |
3  |   Shoes  | 2019-01-02 17:39:34.620 |
4  |   Bags   | 2019-01-02 17:39:34.620 | 
5  |  Shirts  | 2019-01-02 17:39:34.620 |
6  |  Shirts  | 2019-01-03 17:39:34.620 |
7  |  Shirts  | 2019-01-03 17:39:34.620 |  
...

我有有效的PIVOT查询,但没有日期过滤器:

DECLARE @cols NVARCHAR(max) = Stuff((SELECT DISTINCT ', ' + Quotename(Type) 
             FROM   #Tempsa
             FOR xml path(''), type).value('.', 'NVARCHAR(MAX)'), 1, 1, NULL);

EXECUTE('SELECT * FROM (select CAST(Date_and_Time as DATE) AS Transaction_Date, Type, Count(*) n 
                   from  #Tempsa GROUP BY CAST(Date_and_Time as DATE), Type) s
                    PIVOT (max(n) FOR Type IN (' +@cols + ')) pvt')

Output :
Transaction_Date |  Bags | Shirts | Shoes
------------------------------------------
|   2019-01-01   |  1    |  NULL  | NULL |
|   2019-01-02   |  1    |  1     | 2    |
|   2019-01-03   |  NULL |  2     | NULL |
....  

但是,当我在日期过滤器之间使用以下查询时,没有任何记录:

DECLARE @STARTDATE nvarchar(100) = '01/01/2019'
DECLARE @ENDDATE nvarchar(100) = '01/03/2019'

DECLARE @cols NVARCHAR(max) = Stuff((SELECT DISTINCT ', ' + Quotename(Type) 
             FROM   #Tempsa
             FOR xml path(''), type).value('.', 'NVARCHAR(MAX)'), 1, 1, NULL);

EXECUTE('SELECT * FROM (select CAST(Date_and_Time as DATE) AS Transaction_Date, Type, Count(*) n 
                   from  #Tempsa WHERE Date_and_Time BETWEEN ' +@STARTDATE+ ' AND ' +@ENDDATE+' GROUP BY CAST(Date_and_Time as DATE), Type) s
                    PIVOT (max(n) FOR Type IN (' +@cols + ')) pvt')


Output :
Transaction_Date |  Bags | Shirts | Shoes
------------------------------------------
|                |       |        |       |
....

4 个答案:

答案 0 :(得分:6)

只需在日期前后加上引号即可

DECLARE @STARTDATE nvarchar(100) = '01/01/2019'
DECLARE @ENDDATE nvarchar(100) = '01/03/2019'

DECLARE @cols NVARCHAR(max) = Stuff((SELECT DISTINCT ', ' + Quotename(Type) 
             FROM   #Tempsa
             FOR xml path(''), type).value('.', 'NVARCHAR(MAX)'), 1, 1, NULL);

EXECUTE('SELECT * FROM (select CAST(Date_and_Time as DATE) AS Transaction_Date, Type, Count(*) n 
                   from  #Tempsa WHERE Date_and_Time BETWEEN ''' +@STARTDATE+ ''' AND ''' +@ENDDATE+''' GROUP BY CAST(Date_and_Time as DATE), Type) s
                    PIVOT (max(n) FOR Type IN (' +@cols + ')) pvt')

没有双引号,您正在构建如下内容:

BETWEEN 01/01/2011 AND 01/03/2019

这只是由引擎评估的计算

 SELECT 01/01/2011 -- 0
       ,01/03/2019 -- 0

,它是0。因此,您要求获取从00的所有日期。 这就是为什么添加引号会使您的过滤条件有效(以前有效,但是SELECT CAST(0 AS DATETIME)1900-01-01 00:00:00.000,并且由于边界相同,因此不会返回记录)。

当然,您可以使用CONVERT(VARCHAR(10), @STARTDATE, 121)来确保在隐式转换过程中没有任何误解。

答案 1 :(得分:1)

我已经修改了您共享的查询以获得所需的结果。它无法正常工作,因为在合并过滤器的日期时缺少一个非常好的单。现在正在工作。您可以验证相同。

DECLARE @STARTDATE nvarchar(100) = '01/01/2019'
DECLARE @ENDDATE nvarchar(100) = '01/03/2019'

DECLARE @cols NVARCHAR(max) = Stuff((SELECT DISTINCT ', ' + Quotename(Type) 
             FROM   #Tempsa
             FOR xml path(''), type).value('.', 'NVARCHAR(MAX)'), 1, 1, NULL);

EXECUTE( 'SELECT * FROM (select CAST(Date_and_Time as DATE) AS Transaction_Date, Type, Count(*) n 
                   from  #Tempsa WHERE Date_and_Time BETWEEN ''' + @STARTDATE+ ''' AND ''' +@ENDDATE+''' GROUP BY CAST(Date_and_Time as DATE), Type) s
                    PIVOT (max(n) FOR Type IN (' +@cols + ')) pvt')

答案 2 :(得分:0)

将日期写成ISO格式,这样就不会混淆月份和日期。

DECLARE @STARTDATE nvarchar(100) = '2019-01-01'
DECLARE @ENDDATE nvarchar(100) = '2019-01-03'

并确保(以防万一)在动态SQL上进行显式转换。同样,将SQL设置为变量并在执行(使用PRINT)之前先预览它也是一种好方法:

DECLARE @DynamicSQL NVARCHAR(MAX) = '
    SELECT * FROM (select CAST(Date_and_Time as DATE) AS Transaction_Date, Type, Count(*) n 
    from  #Tempsa WHERE Date_and_Time BETWEEN CONVERT(DATE, ''' +@STARTDATE+ ''') AND CONVERT(DATE, ''' + @ENDDATE +''') 
    GROUP BY CAST(Date_and_Time as DATE), Type) s
    PIVOT (max(n) FOR Type IN (' +@cols + ')) pvt'

PRINT (@DynamicSQL)

-- EXECUTE(@DynamicSQL)

答案 3 :(得分:0)

为简化查询,您可以将sp_executesql与如下参数一起使用。

DECLARE @STARTDATE nvarchar(100) = '01/01/2019'
DECLARE @ENDDATE nvarchar(100) = '01/03/2019'

DECLARE @cols NVARCHAR(max) = Stuff((SELECT DISTINCT ', ' + Quotename(Type) 
             FROM   #Tempsa
             FOR xml path(''), type).value('.', 'NVARCHAR(MAX)'), 1, 1, NULL);

declare @SQLString Nvarchar(max)= N'SELECT * FROM (select CAST(Date_and_Time as DATE) AS Transaction_Date, Type, Count(*) n 
                   from  #Tempsa WHERE Date_and_Time BETWEEN @SD  AND @ED GROUP BY CAST(Date_and_Time as DATE), Type) s
                    PIVOT (max(n) FOR Type IN (' +@cols + ')) pvt'
exec sp_executesql @SQLString,N'@SD DATE,@ED DATE',@SD=@STARTDATE,@ED=@ENDDATE

Online Demo