具有独立where子句的多列 - SQL Pivot?

时间:2016-11-20 21:21:31

标签: sql sql-server tsql pivot cross-apply

是否可以采用以下列方式构建的表:

ID    Month     Info1 Info2
1      1          A     B
1      2          C     D
1      3          E     F
2      3          G     H
2      4          I     J

最终会变成这样的表:

ID    JanInfo1 JanInfo2 FebInfo1 FebInfo2 MarInfo1 MarInfo2 AprInfo1 AprInfo2
1        A        B        C        D        E        F        NULL    NULL
2       NULL      NULL    NULL     NULL      G        H         I       J

我已经研究过使用枢轴并且无法让它们工作。

我目前每个月都使用CROSS APPLY表值函数。

有更好的方法吗?

编辑:添加现有查询 - 尝试简化显示:

-- Get the unique IDs
DECLARE @PersonIds TABLE
(
    UploadID UNIQUEIDENTIFIER,
    PersonId VARCHAR(200),
    RecordYear INT
)
INSERT INTO @PersonIds
    SELECT DISTINCT UploadID, PersonId, RecordYear
    FROM [VERTICALTABLE] 
    WHERE UploadID = @PTPUploadID
            AND RecordYear = @RecordYear
        GROUP BY  UploadID, PersonId, RecordYear

-- Flatten via functions
INSERT INTO [FLATTABLE](PersonID, JanuaryCoverage, FebruaryCoverage, MarchCoverage, AprilCoverage, MayCoverage, JuneCoverage, 
        JulyCoverage, AugustCoverage, SeptemberCoverage, OctoberCoverage, NovemberCoverage, DecemberCoverage)

    SELECT PID.PersonID, M1.Covered, M2.Covered, M3.Covered, M4.Covered, M5.Covered, M6.Covered,
        M7.Covered, M8.Covered, M9.Covered, M10.Covered, M11.Covered, M12.Covered
    FROM @PersonIds AS PID
    OUTER APPLY GetMonthInfpo(@PTPUploadID, @RecordYear, 1, PID.PersonId) AS M1
    OUTER APPLY GetMonthInfpo(@PTPUploadID, @RecordYear, 2, PID.PersonId) AS M2
    OUTER APPLY GetMonthInfpo(@PTPUploadID, @RecordYear, 3, PID.PersonId) AS M3
    OUTER APPLY GetMonthInfpo(@PTPUploadID, @RecordYear, 4, PID.PersonId) AS M4
    OUTER APPLY GetMonthInfpo(@PTPUploadID, @RecordYear, 5, PID.PersonId) AS M5
    OUTER APPLY GetMonthInfpo(@PTPUploadID, @RecordYear, 6, PID.PersonId) AS M6
    OUTER APPLY GetMonthInfpo(@PTPUploadID, @RecordYear, 7, PID.PersonId) AS M7
    OUTER APPLY GetMonthInfpo(@PTPUploadID, @RecordYear, 8, PID.PersonId) AS M8
    OUTER APPLY GetMonthInfpo(@PTPUploadID, @RecordYear, 9, PID.PersonId) AS M9
    OUTER APPLY GetMonthInfpo(@PTPUploadID, @RecordYear, 10, PID.PersonId) AS M10
    OUTER APPLY GetMonthInfpo(@PTPUploadID, @RecordYear, 11, PID.PersonId) AS M11
    OUTER APPLY GetMonthInfpo(@PTPUploadID, @RecordYear, 12, PID.PersonId) AS M12
    WHERE UploadID = @PTPUploadID 
        AND RecordYear = @RecordYear

功能看起来像

ALTER FUNCTION GetMonthInfpo( 
(   
    @UploadID UNIQUEIDENTIFIER,
    @Year INT,
    @Month INT,
    @PersonID VARCHAR(200)
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT COUNT(*) AS 'Covered'
    FROM [VERTICALTABLE] 
    WHERE UploadID = @UploadID
        AND RecordYear = @Year
        AND RecordMonth = @Month
        AND PersonId = @PersonID
)

2 个答案:

答案 0 :(得分:2)

您不需要多个子项。答案很简单 - 使用集合论。从您的第一个表ID /月/ Info1 / Info2做ID /月+(1 + 2)/信息与简单联合 - 例如:

select ID, cast(Month as varchar(10)) + cast('_1' as varchar(10)) ComposedMonth, Info1 Info 
from tbl
union all
select ID, cast(Month as varchar(10)) + cast('_2' as varchar(10)), Info2 
from tbl

然后使用此数据集(显示为视图或临时表)pivot子句。

select * 
from vw_tbl t
pivot (max(Info) for ComposedMonth in ([1_1], [1_2]...)) p
-- or if you will cast month to text
-- pivot (max(Info) for ComposedMonth in ([Jan_1], [Jan_2]...)) p

组合字符串是轻松转动的关键。

答案 1 :(得分:1)

使用更新的信息

SELECT
    t.PersonID,
    JanuaryCoverage     = SUM(CASE WHEN t.RecordMonth = 1 THEN Info1 ELSE 0 END),
    FebruaryCoverage    = SUM(CASE WHEN t.RecordMonth = 2 THEN Info1 ELSE 0 END),
    MarchCoverage       = SUM(CASE WHEN t.RecordMonth = 3 THEN Info1 ELSE 0 END),
    AprilCoverage       = SUM(CASE WHEN t.RecordMonth = 4 THEN Info1 ELSE 0 END),
    MayCoverage         = SUM(CASE WHEN t.RecordMonth = 5 THEN Info1 ELSE 0 END),
    JuneCoverage        = SUM(CASE WHEN t.RecordMonth = 6 THEN Info1 ELSE 0 END),
    JulyCoverage        = SUM(CASE WHEN t.RecordMonth = 7 THEN Info1 ELSE 0 END),
    AugustCoverage      = SUM(CASE WHEN t.RecordMonth = 8 THEN Info1 ELSE 0 END),
    SeptemberCoverage   = SUM(CASE WHEN t.RecordMonth = 9 THEN Info1 ELSE 0 END),
    OctoberCoverage     = SUM(CASE WHEN t.RecordMonth = 10 THEN Info1 ELSE 0 END),
    NovemberCoverage    = SUM(CASE WHEN t.RecordMonth = 11 THEN Info1 ELSE 0 END),
    DecemberCoverage    = SUM(CASE WHEN t.RecordMonth = 12 THEN Info2 ELSE 0 END)
FROM [VERTICALTABLE] t
WHERE
    t.UploadID = @UploadID
    AND RecordYear = @Year
GROUP BY t.PersonId;

使用条件聚合:

SELECT
    t.ID,
    JanInfo1    = MAX(CASE WHEN t.[Month] = 1 THEN Info1 END),
    JanInfo2    = MAX(CASE WHEN t.[Month] = 1 THEN Info2 END),
    FebInfo1    = MAX(CASE WHEN t.[Month] = 2 THEN Info1 END),
    FebInfo2    = MAX(CASE WHEN t.[Month] = 2 THEN Info2 END),
    MarInfo1    = MAX(CASE WHEN t.[Month] = 3 THEN Info1 END),
    MarInfo2    = MAX(CASE WHEN t.[Month] = 3 THEN Info2 END),
    AprInfo1    = MAX(CASE WHEN t.[Month] = 4 THEN Info1 END),
    AprInfo2    = MAX(CASE WHEN t.[Month] = 4 THEN Info2 END),
    MayInfo1    = MAX(CASE WHEN t.[Month] = 5 THEN Info1 END),
    MayInfo2    = MAX(CASE WHEN t.[Month] = 5 THEN Info2 END),
    JunInfo1    = MAX(CASE WHEN t.[Month] = 6 THEN Info1 END),
    JunInfo2    = MAX(CASE WHEN t.[Month] = 6 THEN Info2 END),
    JulInfo1    = MAX(CASE WHEN t.[Month] = 7 THEN Info1 END),
    JulInfo2    = MAX(CASE WHEN t.[Month] = 7 THEN Info2 END),
    AugInfo1    = MAX(CASE WHEN t.[Month] = 8 THEN Info1 END),
    AugInfo2    = MAX(CASE WHEN t.[Month] = 8 THEN Info2 END),
    SepInfo1    = MAX(CASE WHEN t.[Month] = 9 THEN Info1 END),
    SepInfo2    = MAX(CASE WHEN t.[Month] = 9 THEN Info2 END),
    OctInfo1    = MAX(CASE WHEN t.[Month] = 10 THEN Info1 END),
    OctInfo2    = MAX(CASE WHEN t.[Month] = 10 THEN Info2 END),
    NovInfo1    = MAX(CASE WHEN t.[Month] = 11 THEN Info1 END),
    NovInfo2    = MAX(CASE WHEN t.[Month] = 11 THEN Info2 END),
    DecInfo1    = MAX(CASE WHEN t.[Month] = 12 THEN Info1 END),
    DecInfo2    = MAX(CASE WHEN t.[Month] = 12 THEN Info2 END)
FROM Tbl t
GROUP BY t.ID;