【问题标题】:SQL Server select columnn as rows dynamically in resultsetSQL Server 在结果集中动态选择列作为行
【发布时间】:2015-07-21 21:00:09
【问题描述】:

我有如下的员工月考勤表。

EmpID    EmpName Month  Year     Day1    Day2    Day3    Day4 .....   Day31

1        ABC      Dec   2014      P       A       WOF     PL           P

在上表中 P - 现在,A - 缺席,WOF - 每周休假,PL - 带薪休假

现在我有以下查询来显示特定月份中的所有天数,如下所示

declare @StartDate DATE
declare @EndDate DATE
set @StartDate = '20141201'
set @EndDate = '20141231';

WITH DateRange AS
 (
     SELECT
         @StartDate Date1
     UNION ALL
     SELECT
         DATEADD(day, 1, T0.Date1) Date
     FROM
         DateRange T0
     WHERE
         T0.Date1 < @EndDate
 )

现在我想要以下格式的结果

EmpId   EmpName   Date         Status

1       ABC       2014-12-01   P
1       ABC       2014-12-02   A
1       ABC       2014-12-03   WOF
1       ABC       2014-12-04   PL
.
.
.
.
.
.
1       ABC       2014-12-31   P

请回复。谢谢。

【问题讨论】:

    标签: sql sql-server sql-server-2008


    【解决方案1】:

    你可以尝试用这部分代码来实现:

    -- Create demo data
    CREATE TABLE #temp(
        empId int, EmpName nvarchar(50), month char(3), year int, 
        day1 varchar(5),day2 varchar(5),day3 varchar(5),day4 varchar(5),day5 varchar(5),day6 varchar(5),day7 varchar(5),
        day8 varchar(5),day9 varchar(5),day10 varchar(5),day11 varchar(5),day12 varchar(5),day13 varchar(5),day14 varchar(5),
        day15 varchar(5),day16 varchar(5),day17 varchar(5),day18 varchar(5),day19 varchar(5),day20 varchar(5),day21 varchar(5),
        day22 varchar(5),day23 varchar(5),day24 varchar(5),day25 varchar(5),day26 varchar(5),day27 varchar(5),day28 varchar(5),
        day29 varchar(5),day30 varchar(5),day31 varchar(5)
    )
    
    INSERT INTO #temp(empId, EmpName, month, year, 
        day1 ,day2 ,day3 ,day4 ,day5 ,day6 ,day7 ,
        day8 ,day9 ,day10 ,day11 ,day12 ,day13 ,day14 ,
        day15 ,day16 ,day17 ,day18 ,day19 ,day20 ,day21 ,
        day22 ,day23 ,day24 ,day25 ,day26 ,day27 ,day28 ,
        day29 ,day30 ,day31)
    VALUES(1,N'Employee1',N'Dec',2014,
        N'A',N'B',N'C',N'D',N'E',N'F',N'G',
        N'A',N'B',N'C',N'D',N'E',N'F',N'G',
        N'A',N'B',N'C',N'D',N'E',N'F',N'G',
        N'A',N'B',N'C',N'D',N'E',N'F',N'G',
        N'X',N'Y',N'Z')
    
    -- Your Part
    SELECT unpvt.empId, unpvt.EmpName, 
        -- do the day trick
        CONVERT(date,
            CONVERT(nvarchar(max),unpvt.year)+N'-'
            +CONVERT(nvarchar(max),unpvt.month)+N'-'
            +REPLACE(unpvt.dayCol,N'Day',N'')
        ,106) as [Date], 
        value as [Status]
    FROM #temp
    UNPIVOT(
        value
        FOR dayCol IN([day1],[day2],[day3],[day4],[day5],[day6],[day7],
                [day8],[day9],[day10],[day11],[day12],[day13],[day14],
                [day15],[day16],[day17],[day18],[day19],[day20],[day21],
                [day22],[day23],[day24],[day25],[day26],[day27],[day28],
                [day29],[day30],[day31])
    ) as unpvt
    
    -- Cleanup
    DROP TABLE #temp
    

    我正在使用UNPIVOT 将列转换为行。之后,我替换列名以获取日期编号并从中生成datetime 列。

    但除此之外,这会解决你的问题,桌子设计真的很糟糕。无论如何,我确信你没有设计这个,你只需要处理它。 :-)

    【讨论】:

      【解决方案2】:

      你可以像这样使用UNPIVOT

      查询

      SELECT EmpID,EmpName,
      CONVERT(DATE,REPLACE(Col,'Day','') + ' ' + [Month] + ' ' + CONVERT(VARCHAR(20),[Year]),106) AttDate,
      Val
      FROM EmpATT
      UNPIVOT(Val FOR Col IN([Day1], [Day2], [Day3], [Day4], [Day31])) as UPVT
      

      输出

      | EmpID | EmpName |    AttDate | Val |
      |-------|---------|------------|-----|
      |     1 |     ABC | 2014-12-01 |   P |
      |     1 |     ABC | 2014-12-02 |   A |
      |     1 |     ABC | 2014-12-03 | WOF |
      |     1 |     ABC | 2014-12-04 |  PL |
      |     1 |     ABC | 2014-12-31 |   P |
      

      SQL Fiddle

      【讨论】:

        【解决方案3】:

        试试这个,以便动态地将列设置为几天。

        declare @columnName nvarchar(max) = ''
        declare @ex nvarchar(max) = ''
        
        select @columnName += quotename(COLUMN_NAME) + ',' from (select * from INFORMATION_SCHEMA.COLUMNS
        where TABLE_NAME = 'DateRange' and COLUMN_NAME like 'day%')
        
        
        set @columnName = LEFT(@columnname,len(@columnname) - 1)
        
        
        set @ex = '
        select .... from DateRange
        pivot ....
        for ....
        in (' + @columnName+ ')) as pivotT'
        
        exec sp_executesql @ex
        

        【讨论】:

          猜你喜欢
          • 2021-02-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-15
          • 2014-05-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多