【问题标题】:Assign default values in SQL Server dynamic pivot在 SQL Server 动态数据透视中分配默认值
【发布时间】:2020-04-07 22:26:17
【问题描述】:

下面是我的要求的透视查询。

DECLARE @cols NVARCHAR(MAX) = '';

;WITH log_date AS 
(
    SELECT 
        BatchStartDate AS l_date 
    FROM 
        Table_Batch_Lookup

    UNION ALL

    SELECT 
        DATEADD(dd, 1, l_date) 
    FROM 
        log_date AS ld, Table_Batch_Lookup AS tb  
    WHERE 
        ld.l_date < DATEADD(dd, -1, tb.BatchEndDate)
)
SELECT 
    @cols = COALESCE (@cols + ',[' + CONVERT(NVARCHAR,CONVERT(VARCHAR(10), l_Date, 111), 106) + ']','[' + CONVERT(NVARCHAR, l_Date, 106) + ']') 
FROM 
    (SELECT DISTINCT CONVERT(VARCHAR(10), l_Date, 111) AS l_date 
     FROM log_date) PV;

DECLARE @totalScore INT = LEN(@cols) - LEN(REPLACE(@cols, ',', ''))

DECLARE @query NVARCHAR(MAX); 

SET @query = 'SELECT t_info.TraineeID,t_batch.BatchId,t_info.Name,t_info.Mobile'+@cols+'  FROM  Table_TraineeInfo AS t_info  Left JOIN       
                  (SELECT * FROM 
                 (
                     SELECT TraineeID,BatchId,Attendance,CONVERT(VARCHAR(10), l_Date, 111) AS l_date FROM Table_Attendance_Log
                 ) x
                 PIVOT 
                 (
                     MAX(Attendance)
                     FOR l_Date IN (' + right(@cols, len(@cols)-1)+ ')
                ) p ) AS f_pv ON t_info.TraineeID=f_pv.TraineeID JOIN Table_Batch_Lookup as t_batch ON t_batch.BatchId=t_info.BatchId

                WHERE t_batch.BatchId=45;
                ' ;    
    EXEC SP_EXECUTESQL @query;

下面是我的带有数据的表创建脚本的脚本。 Table_TraineeInfo是候选人注册明细表,Table_Batch_Lookup是批次开始日期和结束日期基于填写数据透视表时的批次明细, Table_Attendance_Log是考生考勤记录。

CREATE TABLE [dbo].[Table_TraineeInfo]
(
    [TraineeID] [INT] NULL,
    [BatchId] [INT] NULL,
    [Name] [VARCHAR](MAX) NULL,
    [Mobile] [VARCHAR](10) NULL
) ON [PRIMARY]
GO

SET ANSI_PADDING OFF
GO
INSERT [dbo].[Table_TraineeInfo] ([TraineeID], [BatchId], [Name], [Mobile]) 
VALUES (243, 45, N'demo201', N'9888562341'),
       (244, 45, N'demo202', N'9888562342'),
       (246, 45, N'demo204', N'9888562344'),
       (247, 45, N'demo205', N'9999999999')

/****** Object:  Table [dbo].[Table_Batch_Lookup]    Script Date: 12/15/2019 04:34:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Table_Batch_Lookup]
(
    [BatchId] [INT] NULL,
    [BatchStartDate] [DATETIME] NULL,
    [BatchEndDate] [DATETIME] NULL
) ON [PRIMARY]
GO

INSERT [dbo].[Table_Batch_Lookup] ([BatchId], [BatchStartDate], [BatchEndDate]) 
VALUES (45, CAST(0x0000AB2200000000 AS DateTime), CAST(0x0000AB25018B80D4 AS DateTime))

/****** Object:  Table [dbo].[Table_Attendance_Log]    Script Date: 12/15/2019 04:34:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[Table_Attendance_Log]
(
    [TraineeID] [INT] NULL,
    [BatchId] [INT] NULL,
    [Attendance] [VARCHAR](10) NULL,
    [l_date] [DATETIME] NULL
) ON [PRIMARY]
GO

SET ANSI_PADDING OFF
GO

INSERT [dbo].[Table_Attendance_Log] ([TraineeID], [BatchId], [Attendance], [l_date]) 
VALUES (243, 45, N'Present', CAST(0x0000AB220127842A AS DateTime)),
       (243, 45, N'Present', CAST(0x0000AB2301281C2A AS DateTime)),
       (243, 45, N'Present', CAST(0x0000AB240128E416 AS DateTime)),
       (244, 45, N'Present', CAST(0x0000AB24012A05AB AS DateTime)),
       (246, 45, N'Present', CAST(0x0000AB23012B245A AS DateTime)),
       (246, 45, N'Present', CAST(0x0000AB24012B245A AS DateTime))

我当前的输出

如果日期小于或等于今天的日期,我希望下面的输出将空值填充到缺席(过去的日期),而未来的日期应该是 2019 年 12 月 16 日没有缺席的未来日期不需要填写缺席。

【问题讨论】:

    标签: sql sql-server date sql-server-2008 pivot


    【解决方案1】:

    在常规(即非动态)透视查询中,当聚合函数产生null 时,您通常使用COALESCE() 来分配默认值。

    这对于您的动态 SQL 来说有点复杂。基本上,您需要设置第二个变量来保存要放入 SELECT 子句中的 COALESCE() 表达式。我叫它@select_cols;我们使用COALESCE()CASE 表达式在分配默认值之前检查日期是否为未来。

    这是您的更新代码:

    Declare @cols NVARCHAR(Max)='';
    Declare @select_cols NVARCHAR(Max)='';
    
    ;With log_date AS (
        SELECT BatchStartDate as l_date FROM Table_Batch_Lookup
        UNION ALL
        SELECT DATEADD(dd, 1, l_date)
        FROM log_date AS ld, Table_Batch_Lookup AS tb 
        WHERE ld.l_date < DATEADD(dd, -1, tb.BatchEndDate)
    )
    SELECT 
        @cols = COALESCE (
            @cols + ',[' + CONVERT(NVARCHAR,CONVERT(VARCHAR(10), l_Date, 111), 106) + ']',
            '[' + CONVERT(NVARCHAR, l_Date, 106) + ']'
        ), 
        @select_cols = COALESCE (
            @select_cols 
                + ',COALESCE([' + CONVERT(NVARCHAR,CONVERT(VARCHAR(10), l_Date, 111), 106) 
                + '], ' + CASE WHEN CONVERT(DATE, l_Date, 111) <= GETDATE() 
                    THEN '''Absent''' 
                    ELSE '''NULL''' 
                END + ') AS [' 
                + CONVERT(NVARCHAR,CONVERT(VARCHAR(10), l_Date, 111), 106) + ']',
            '[' + CONVERT(NVARCHAR, l_Date, 106) + ']'
        )
    FROM (SELECT DISTINCT CONVERT(VARCHAR(10), l_Date, 111) AS l_date FROM log_date) PV
    
    Declare @totalScore INT =len(@cols) - len(replace(@cols, ',', ''))
    
    DECLARE @query NVARCHAR(MAX); 
    SET @query = 'SELECT 
            t_info.TraineeID,
            t_batch.BatchId,
            t_info.Name,
            t_info.Mobile'
            + @select_cols + '
        FROM  Table_TraineeInfo AS t_info  
        LEFT JOIN (
                SELECT * FROM (
                     SELECT 
                         TraineeID,
                         BatchId,
                         Attendance,
                         CONVERT(VARCHAR(10), l_Date, 111) AS l_date 
                     FROM Table_Attendance_Log
                ) x
                PIVOT (
                     MAX(Attendance)
                     FOR l_Date IN (' + right(@cols, len(@cols)-1)+ ')
                ) p 
        ) AS f_pv ON t_info.TraineeID=f_pv.TraineeID 
        JOIN Table_Batch_Lookup as t_batch ON t_batch.BatchId=t_info.BatchId
        WHERE t_batch.BatchId=45';  
    
    EXEC SP_EXECUTESQL @query;
    

    Demo on DB Fiddle

    实习生ID |批号 |姓名 |手机 | 2019/12/13 | 2019/12/14 | 2019/12/15 | 2019/12/16 --------: | ------: | :-------- | :--------- | :--------- | :--------- | :--------- | :--------- 243 | 45 |演示201 | 9888562341 |礼物 |礼物 |礼物 |空值 244 | 45 |演示202 | 9888562342 |缺席 |缺席 |礼物 |空值 246 | 45 |演示204 | 9888562344 |缺席 |礼物 |礼物 |空值 247 | 45 |演示205 | 9999999999 |缺席 |缺席 |缺席 |空值

    【讨论】:

    • 我不希望 2019/12/16 日期缺席,因为它的未来日期,请检查我的输出。 @GMB
    • 我的输出不同。 @GMB
    • 你在吗? @GMB
    • 欢迎您@mohdmazharkhan。并且为了您的信息,我不是对您的问题投反对票的人(实际上我投了赞成票,因为我发现它很有趣并且有据可查)。
    猜你喜欢
    • 2014-10-16
    • 2014-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-09
    • 2018-11-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多