【问题标题】:SQL pivot table cross apply over counting resultsSQL 数据透视表交叉应用计数结果
【发布时间】:2014-02-24 14:26:06
【问题描述】:

我正在使用具有动态创建列的数据透视表来创建按月计算操作数的报告。在动态查询中是一个涉及三列的 CROSS APPLY。这导致我的总数是他们应该的三倍。我目前正在破解一个解决方案,将计数除以三以获得正确答案。谁能帮我想出一个更优雅的解决方案来解决这个问题?

编辑:我使用的是 SQL Server 2008R2

鉴于这个数据集(它实际上是一个视图,但我觉得在 SO 中重新创建整个架构并不明智):

CREATE TABLE vw_ActionsReport
    ([CID] int, [MitigationActionID] int, [Approved] int, [Status] varchar(11), [ChangedDate] datetime, [EntryDate] varchar(7), [STATE_ABBR] varchar(2), [STATE_NAME] varchar(11), [CENSUS_NAM] varchar(12), [CIS_NAME] varchar(21), [COUNTY_NAM] varchar(9), [CO_FIPS] int, [REGION] int, [ST_FIPS] int);

INSERT INTO vw_ActionsReport
    ([CID], [MitigationActionID], [Approved], [Status], [ChangedDate], [EntryDate], [STATE_ABBR], [STATE_NAME], [CENSUS_NAM], [CIS_NAME], [COUNTY_NAM], [CO_FIPS], [REGION], [ST_FIPS])
VALUES
    (090069, 5475, 1, 'Identified', '2012-11-27 16:21:27', '11_2012', 'CT', 'CONNECTICUT', 'OLD SAYBROOK', 'OLD SAYBROOK, TOWN OF', 'MIDDLESEX', 09007, 01, 09),
    (090069, 5476, 1, 'In Progress', '2012-11-27 16:21:27', '11_2012', 'CT', 'CONNECTICUT', 'OLD SAYBROOK', 'OLD SAYBROOK, TOWN OF', 'MIDDLESEX', 09007, 01, 09),
    (090012, 6687, 1, 'Identified', '2013-04-02 16:14:03', '4_2013', 'CT', 'CONNECTICUT', 'NORWALK', 'NORWALK, CITY OF', 'FAIRFIELD', 09001, 01, 09),
    (090008, 6993, 1, 'Identified', '2013-06-20 15:18:38', '6_2013', 'CT', 'CONNECTICUT', 'GREENWICH', 'GREENWICH, TOWN OF', 'FAIRFIELD', 09001, 01, 09),
    (090019, 17000, 0, 'Identified', '2013-11-26 11:46:14', '11_2013', 'CT', 'CONNECTICUT', 'WESTPORT', 'WESTPORT, TOWN OF', 'FAIRFIELD', 09001, 01, 09);

然后,使用以下查询:

DECLARE @cols AS NVARCHAR(MAX),
        @cols_math AS NVARCHAR(MAX),
        @query AS NVARCHAR(MAX);

SELECT @cols = STUFF
        (
          (
            SELECT ',' + QUOTENAME(EntryDate)
            FROM dbo.vw_ActionsReport
            GROUP BY EntryDate,
                     DATEPART(YEAR, dbo.vw_ActionsReport.ChangedDate),
                     DATEPART(MONTH, dbo.vw_ActionsReport.ChangedDate)
            ORDER BY DATEPART(YEAR, dbo.vw_ActionsReport.ChangedDate),
                     DATEPART(MONTH, dbo.vw_ActionsReport.ChangedDate)
            FOR XML PATH(''), TYPE
          ).value('.', 'NVARCHAR(MAX)'),
          1,1,''
        );

SELECT @cols_math = STUFF
        (
          (
            -- This is my hack where I divide the answer by three
            SELECT ',' + QUOTENAME(EntryDate) + ' / 3 AS ' + QUOTENAME(EntryDate)
            FROM dbo.vw_ActionsReport
            GROUP BY EntryDate,
                     DATEPART(YEAR, dbo.vw_ActionsReport.ChangedDate),
                     DATEPART(MONTH, dbo.vw_ActionsReport.ChangedDate)
            ORDER BY DATEPART(YEAR, dbo.vw_ActionsReport.ChangedDate),
                     DATEPART(MONTH, dbo.vw_ActionsReport.ChangedDate)
            FOR XML PATH(''), TYPE
          ).value('.', 'NVARCHAR(MAX)'),
          1,1,''
        );

SET @query = 'SELECT REGION, STATE_ABBR, [Status],' + @cols_math + ' FROM
             (
                SELECT REGION, STATE_ABBR, [Status], EntryDate, MitigationActionID
                FROM dbo.vw_ActionsReport
                CROSS APPLY
                (
                  SELECT CAST(REGION AS VARCHAR(50)) UNION ALL
                  SELECT CAST(STATE_ABBR AS VARCHAR(50)) UNION ALL
                  SELECT CAST([Status] AS VARCHAR(50))
                ) c(col)
             ) x
             PIVOT
             (
                COUNT(MitigationActionID)
                FOR EntryDate IN (' + @cols + ')
             ) p ';

EXECUTE(@query);

输出应如下所示:

+-REGION-+-STATE_ABBR-+-Status------+-11_2012-+-4_2013-+-6_2013-+-11_2013-+
| 01     | CT         | Identified  | 1       | 1      | 1      | 1       |
| 01     | CT         | In Progress | 1       | 0      | 0      | 0       |

如果我不包括我的 hack,如查询中的注释中所示,输出表中的所有 1 都将变为 3。我很确定它来自 CROSS APPLY,因为如果我更改 CROSS APPLY 中的 SELECTS 数量,总数也会以同样的方式变化。

我确信有更好的方法可以做到这一点,但我没有成功。我花了很多时间试图让 DISTINCT 工作,但我似乎无法让 COUNT DISTINCT 在 PIVOT 内工作。

如果有人可以给我任何建议,我将不胜感激。

【问题讨论】:

  • COUNT(DISTINCT MitigationActionID) 工作吗?
  • @NickyvV,不,我花了很多时间试图让它工作,但找不到解决方案。我得到Incorrect syntax near the keyword 'DISTINCT'.

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


【解决方案1】:

问题是您正在应用 CROSS APPLY 而您不需要。通常你会使用 CROSS APPLY 或 UNPIVOT,如果你需要旋转多列但你只旋转一列,所以 unpivot 是不必要的。

查询应该是这样的:

SELECT region, STATE_ABBR,
  [Status], 
  [11_2012], [4_2013], [6_2013], [11_2013]
FROM
(
  SELECT REGION, STATE_ABBR, 
    [Status], EntryDate, 
    MitigationActionID
  FROM dbo.vw_ActionsReport
) x
PIVOT
(
  COUNT(MitigationActionID)
  FOR EntryDate IN ([11_2012], [4_2013], [6_2013], [11_2013])
) p;

SQL Fiddle with Demo

那么您的动态 SQL 代码将是:

DECLARE @cols AS NVARCHAR(MAX),
        @query AS NVARCHAR(MAX)

SELECT @cols = STUFF
        (
          (
            SELECT ',' + QUOTENAME(EntryDate)
            FROM dbo.vw_ActionsReport
            GROUP BY EntryDate,
                     DATEPART(YEAR, dbo.vw_ActionsReport.ChangedDate),
                     DATEPART(MONTH, dbo.vw_ActionsReport.ChangedDate)
            ORDER BY DATEPART(YEAR, dbo.vw_ActionsReport.ChangedDate),
                     DATEPART(MONTH, dbo.vw_ActionsReport.ChangedDate)
            FOR XML PATH(''), TYPE
          ).value('.', 'NVARCHAR(MAX)'),
          1,1,''
        );

SET @query = 'SELECT REGION, STATE_ABBR, [Status],' + @cols + ' 
              FROM
              (
                SELECT REGION, STATE_ABBR, 
                  [Status], EntryDate, 
                  MitigationActionID
                FROM dbo.vw_ActionsReport
             ) x
             PIVOT
             (
                COUNT(MitigationActionID)
                FOR EntryDate IN (' + @cols + ')
             ) p ';

EXECUTE(@query);

SQL Fiddle with Demo。通过使用此代码,您将获得以下结果:

| REGION | STATE_ABBR |      STATUS | 11_2012 | 4_2013 | 6_2013 | 11_2013 |
|--------|------------|-------------|---------|--------|--------|---------|
|      1 |         CT |  Identified |       1 |      1 |      1 |       1 |
|      1 |         CT | In Progress |       1 |      0 |      0 |       0 |

【讨论】:

    猜你喜欢
    • 2012-04-07
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 2017-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多