在单元格中使用n / m格式的数据透视表 - 两个用斜杠分隔的值

时间:2017-06-30 09:16:43

标签: sql-server tsql

我的表包含如下聚合数据:

Name | Data       | Status | Count
----------------------------------
A    | 2017-06-01 | ok     | 2
A    | 2017-06-01 | error  | 5
A    | 2017-06-02 | ok     | 3
A    | 2017-06-02 | error  | 1
A    | 2017-06-03 | ok     | 5
B    | 2017-06-01 | ok     | 1
B    | 2017-06-01 | error  | 7
B    | 2017-06-02 | ok     | 3
B    | 2017-06-02 | error  | 3
B    | 2017-06-03 | error  | 2

现在我正在尝试使用名称作为列创建数据透视表,将日期作为行创建。在单元格内部,我想获得状态为{1}}

错误状态的行数为ok的数字或行数

以下是我想要的表格:

2/5

因为我在Data | A | B ------------------------ 2017-06-01 | 2/5 | 1/7 2017-06-02 | 3/1 | 3/3 2017-06-03 | 5/- | -/2 列中可以有不同的值,所以我创建了动态查询来获取这些值。

我的代码如下所示:

Name

但是我获得了两次行(可能是因为我没有按状态分组)。

如何获得我需要的结果?

我在sqlfiddle中构建了示例:http://sqlfiddle.com/#!6/31770/3

4 个答案:

答案 0 :(得分:0)

您可以在旋转之前计算TotalOk / TotalError

CREATE TABLE TMP
    (
     Name VARCHAR(50)
    ,Data VARCHAR(10)
    ,Status VARCHAR(20)
    ,Count INT
    )
;

INSERT INTO TMP
    (Name, Data, Status,Count)
VALUES
    ('A', '2017-06-01', 'ok',2),
    ('A', '2017-06-01', 'error',5),
    ('A', '2017-06-02', 'ok',3),
    ('A', '2017-06-02', 'error',1),
    ('A', '2017-06-03', 'ok',5),
    ('B', '2017-06-01', 'ok',2),
    ('B', '2017-06-01', 'error',5),
    ('B', '2017-06-02', 'ok',3),
    ('B', '2017-06-02', 'error',1),
    ('B', '2017-06-03', 'error',2)
;

DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)

SELECT
    @ColumnName = ISNULL(@ColumnName + ',', '') + QUOTENAME(Name)
FROM
    ( SELECT DISTINCT
        Name
      FROM
        TMP
    ) AS Courses


SET @DynamicPivotQuery = N'
    SELECT Data, ' + @ColumnName + '
    FROM 
    (   SELECT 
      t.Name, t.Data,
      CONCAT(    NULLIF(SUM(CASE WHEN t.Status = ''ok'' THEN t.Count ELSE 0 END),0),
             ''/'', 
             NULLIF(SUM(CASE WHEN t.Status = ''ok'' THEN 0 ELSE t.Count END),0)
            ) AS Count
       FROM dbo.TMP t
       GROUP BY t.Name, t.Data
    ) src
    PIVOT
    (
       MAX(Count)
        FOR Name IN (' + @ColumnName + ')
    ) AS PVTTable'


EXEC sp_executesql @DynamicPivotQuery


DROP TABLE dbo.TMP

演示链接:http://rextester.com/TMAVV39610

答案 1 :(得分:0)

示例数据

IF OBJECT_ID('Tempdb..#Temp') IS NOT NULL
Drop table #Temp
;With cte(Name , Data, Status , [Count])
AS
(
SELECT 'A','2017-06-01' , 'ok'     , 2 UNION ALL
SELECT 'A','2017-06-01' , 'error'  , 5 UNION ALL
SELECT 'A','2017-06-02' , 'ok'     , 3 UNION ALL
SELECT 'A','2017-06-02' , 'error'  , 1 UNION ALL
SELECT 'A','2017-06-03' , 'ok'     , 5 UNION ALL
SELECT 'B','2017-06-01' , 'ok'     , 1 UNION ALL
SELECT 'B','2017-06-01' , 'error'  , 7 UNION ALL
SELECT 'B','2017-06-02' , 'ok'     , 3 UNION ALL
SELECT 'B','2017-06-02' , 'error'  , 3 UNION ALL
SELECT 'B','2017-06-03' , 'error'  , 2
)
SELECT * INTO #Temp From cte

SELECT * FRom #Temp

以下方法通过动态SQL方法提供您的预期结果

DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX),@ColumnName2 AS NVARCHAR(MAX)

SELECT @ColumnName=STUFF((SELECT DISTINCT ', '+ QUOTENAME(Name) FROM  #Temp FOR  XML PATH ('')),1,1,'')

SELECT @ColumnName2=
STUFF((SELECT DISTINCT ', '+ 'REPLACE(ISNULL('+ QUOTENAME(Name) +','+'''0'''+')'+','+'''0'''+','+'''-'''+') AS '
                           + QUOTENAME(Name) FROM  #Temp FOR  XML PATH ('')),1,1,'')


SET @DynamicPivotQuery=N'
                        ;With Cte
                          AS
                            (
                                SELECT Data,'+@ColumnName2+'From 
                                (
                                SELECT * FROM #Temp 
                                ) AS SRC
                            PIVOT
                                (
                                SUM([Count]) FOR Name IN ('+@ColumnName+')
                                )
                            PVT
                            )
                            SELECT Data ,[A],[B]
                                    FROM (
                                        SELECT DATA ,STUFF((SELECT ''/'' + CAST([A] AS VARCHAR(5))  FROM CTE I
                                                    WHERE I.DATA = O.DATA ORDER BY 1 DESC
                                                    FOR XML PATH('''')), 1, 1, '''') AS [A]
                                            ,STUFF((
                                                    SELECT ''/'' + CAST([B] AS VARCHAR(5))  FROM CTE I
                                                    WHERE I.DATA = O.DATA ORDER BY 1 
                                                    FOR XML PATH('''')), 1, 1, '''') AS [B]
                                            ,ROW_NUMBER() OVER (PARTITION BY DATA ORDER BY DATA ) AS SEQ
                                        FROM CTE O
                                        ) DT
                                    WHERE DT.SEQ = 1
                            '

PRINT @DynamicPivotQuery

EXEC sp_executesql @DynamicPivotQuery

静态方法

 ;WITH cte
    AS (
        SELECT DISTINCT Data
            ,REPLACE(ISNULL([A], '0'), '0', '-') AS [A]
            ,REPLACE(ISNULL([B], '0'), '0', '-') AS [B]
        FROM (
            SELECT *
            FROM #Temp
            ) AS SRC
        PIVOT(SUM([Count]) FOR NAME IN (
                    [A]
                    ,[B]
                    )) PVT
        )
    SELECT Data
        ,[A]
        ,[B]
    FROM (
        SELECT DATA
            ,STUFF((
                    SELECT '/' + CAST([A] AS VARCHAR(5))
                    FROM CTE I
                    WHERE I.DATA = O.DATA
                    ORDER BY 1 DESC
                    FOR XML PATH('')
                    ), 1, 1, '') AS [A]
            ,STUFF((
                    SELECT '/' + CAST([B] AS VARCHAR(5))
                    FROM CTE I
                    WHERE I.DATA = O.DATA
                    ORDER BY 1
                    FOR XML PATH('')
                    ), 1, 1, '') AS [B]
            ,ROW_NUMBER() OVER (
                PARTITION BY DATA ORDER BY DATA
                ) AS SEQ
        FROM CTE O
        ) DT
    WHERE DT.SEQ = 1

结果

Data       | A   | B 
------------------------
2017-06-01 | 2/5 | 1/7
2017-06-02 | 3/1 | 3/3
2017-06-03 | 5/- | -/2

答案 2 :(得分:0)

也许这可以给你一个想法。

示例数据:

 IF (OBJECT_ID('tempdb..#TMP') IS NOT NULL)
 BEGIN
    DROP TABLE #TMP

 END

   CREATE TABLE #TMP 
    (
      id INT IDENTITY(1, 1)
             PRIMARY KEY ,
      NAME VARCHAR(10) ,
      DATA DATETIME ,
      [Status] VARCHAR(20) ,
      [Count] INT
    )
   DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
   INSERT   INTO #TMP
            ( NAME, DATA, Status, Count )
   VALUES   ( 'A', '2017-06-01', 'ok', 2 ),
            ( 'A', '2017-06-01', 'error', 5 ),
            ( 'A', '2017-06-02', 'ok', 3 ),
            ( 'A', '2017-06-02', 'error', 1 ),
            ( 'A', '2017-06-03', 'ok', 5 ),
            ( 'B', '2017-06-01', 'ok', 1 ),
            ( 'B', '2017-06-01', 'error', 7 ),
            ( 'B', '2017-06-02', 'ok', 3 ),
            ( 'B', '2017-06-02', 'error', 3 ),
            ( 'B', '2017-06-03', 'error', 2 )

QUERY:

   DECLARE @ColumnName AS NVARCHAR(MAX)

   SELECT   @ColumnName = ISNULL(@ColumnName + ',', '') + QUOTENAME(Name)
   FROM     ( SELECT DISTINCT
                        Name
              FROM      #TMP
            ) AS Courses

  SET @DynamicPivotQuery = N'

   SELECT   CAST(DATA AS DATE) DATA,
            ' + @ColumnName + '
   FROM     ( SELECT    name ,
                        data ,
                        REPLACE(CAST([A] AS VARCHAR(10)) + ''/''
                                + CAST([B] AS VARCHAR(10)), ''0'', ''-'') COL
              FROM      ( SELECT    t1.name ,
                                    t1.data ,
                                    ISNULL(t1.COUNT, 0) [A] ,
                                    ISNULL(T2.Count, 0) [B]
                          FROM      ( SELECT    NAME ,
                                                DATA ,
                                                Status ,
                                                Count
                                      FROM      #TMP
                                      WHERE     Status = ''ok''
                                    ) T1
                                    LEFT JOIN ( SELECT  NAME ,
                                                        DATA ,
                                                        Status ,
                                                        Count
                                                FROM    #TMP
                                                WHERE   Status = ''error''
                                              ) T2 ON T2.NAME = T1.NAME
                                                      AND T2.DATA = T1.DATA
                          UNION ALL
                          SELECT    t2.name ,
                                    t2.data ,
                                    ISNULL(t1.COUNT, 0) [A] ,
                                    ISNULL(T2.Count, 0) [B]
                          FROM      ( SELECT    NAME ,
                                                DATA ,
                                                Status ,
                                                Count
                                      FROM      #TMP
                                      WHERE     Status = ''error''
                                    ) T2
                                    LEFT JOIN ( SELECT  NAME ,
                                                        DATA ,
                                                        Status ,
                                                        Count
                                                FROM    #TMP
                                                WHERE   Status = ''ok''
                                              ) T1 ON T2.NAME = T1.NAME
                                                      AND T2.DATA = T1.DATA
                        ) TT
            ) P PIVOT ( MAX(col) FOR name IN ( '+ @ColumnName + ' ) ) PVT'


        EXEC(@DynamicPivotQuery)

结果:

            DATA        A           B
            ----------  ----------- ----------
            2017-06-01  2/5         1/7
            2017-06-02  3/1         3/3
            2017-06-03  5/-         -/2

            (3 row(s) affected)

答案 3 :(得分:0)

首先,你在B的小提琴中写错了数据(所以也许你看不到部分预期的结果)。 我想你可以尝试这样的事情(我只是改变了一下最后一个查询,在一个字符串中聚合'ok'和'error':

DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)

SELECT
    @ColumnName = ISNULL(@ColumnName + ',', '') + QUOTENAME(Name)
FROM
    ( SELECT DISTINCT
        Name
      FROM
        TMP
    ) AS Courses   

    SET @DynamicPivotQuery ='
    SELECT * FROM 
    (SELECT Data, NAME, MAX(CASE WHEN STATUS=''ok'' THEN CAST(COUNT AS VARCHAR(8)) 
            ELSE ''-'' END)   +''/''
        + MAX(CASE WHEN STATUS=''error'' THEN CAST(COUNT AS VARCHAR(8)) ELSE ''-'' END)  AS C   
        FROM TMP  
        GROUP BY DATA, NAME) X
        PIVOT ( MAX(C) FOR Name IN (' + @ColumnName + ')) AS PVTTable'   

    EXEC sp_executesql @DynamicPivotQuery

输出:

Data        A   B
2017-06-01  2/5 1/7
2017-06-02  3/1 3/3
2017-06-03  5/- -/2

更新版本:

SET @DynamicPivotQuery ='
    SELECT *
    FROM (SELECT Y.DATA, Y.NAME,   MAX(CASE WHEN STATUS=''ok'' THEN CAST(COUNT AS VARCHAR(8)) ELSE ''-'' END)   +''/''
    + MAX(CASE WHEN STATUS=''error'' THEN CAST(COUNT AS VARCHAR(8)) ELSE ''-'' END)   AS C  
    FROM TMP
    RIGHT JOIN (SELECT DISTINCT TMP.NAME, Z.DATA
                FROM TMP  CROSS JOIN (SELECT DISTINCT DATA FROM TMP ) Z) Y ON TMP.NAME = Y.NAME AND TMP.DATA = Y.DATA   
    GROUP BY Y.DATA, Y.NAME) X
    PIVOT ( MAX(C) FOR Name IN (' + @ColumnName + ')) AS PVTTable'