【问题标题】:Convert horizontal table to vertical in Sql在Sql中将水平表转换为垂直表
【发布时间】:2018-07-23 16:29:32
【问题描述】:

我的表格格式如下:

我需要将此表转换为以下格式:

我在其他问题中寻找 PIVOT 函数,但输入表中的“键”值不是一组固定的值,它们可以是任何值。我还寻找其他此类问题,但我不确定应该如何编写查询。

我的代码是:

SELECT
    ROW_NUMBER () OVER (
ORDER BY RouteCode) AS SrNo
, RouteCode AS X
, SUM(Units) AS Y
FROM
    [ INTERFACE_ok ] .[ dbo ] .[ v_A40OrdersBhQt ]
WHERE [ DeliveryDate ] > CAST(
        FLOOR(CAST(GETDATE () AS FLOAT)) AS DATETIME
    )
    AND CustomerCode LIKE '900%'
GROUP BY [ RouteCode ]

任何帮助将不胜感激,谢谢!

【问题讨论】:

  • 你的 dbms 是什么? mysql 或 sqlserver 或其他?
  • 我的 dbms 是 Sqlserver
  • 好的我已经回答了你的问题,有一个sqlserver解决方案。 @Leace

标签: sql sql-server pivot pivot-table


【解决方案1】:

您正在寻找Dynamics pivot

主要步骤如下

  1. 声明变量 @sqlX@sqlY 以承载您的 MAX 函数和 CASW WHEN 表达式以创建 XY 枢轴列。
  2. 使用CONCAT 将您的SUM 函数和CASW WHEN 表达式字符串和主选择字符串以及UNION ALL @sqlX@sqlY 查询字符串结合起来。
  3. 使用EXECUTE函数动态执行SQL。

TestDLL

CREATE TABLE T(
  SrNo INT,
  X  VARCHAR(100),
  Y INT
);

INSERT INTO T VALUES (1,'N1',100);
INSERT INTO T VALUES (2,'N2',200);
INSERT INTO T VALUES (3,'N3',300);
INSERT INTO T VALUES (4,'N4',400);
INSERT INTO T VALUES (5,'N5',500);
INSERT INTO T VALUES (6,'N6',600);
INSERT INTO T VALUES (7,'N7',700);

这里是mysql示例。

SET @sqlX = NULL;
SET @sqlY = NULL;
SET @sql = NULL;

SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'MAX(CASE WHEN SrNo =',
      SrNo,
      ' THEN X END) '
    )
  ) INTO @sqlX
FROM T;

SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'MAX(CASE WHEN SrNo =',
      SrNo,
      ' THEN Y END) '
    )
  ) INTO @sqlY
FROM T;

SET @sql = CONCAT('SELECT ''X'', ', @sqlX, ' 
                   FROM T
                   UNION ALL
                   SELECT ''Y'', ', @sqlY, '
                   FROM T
                   ');


PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

Mysql sqlfiddle

SQL-Server 版本

DECLARE @sqlX VARCHAR(MAX)
DECLARE @sqlY VARCHAR(MAX)
DECLARE @sql VARCHAR(MAX)

SET @sqlX = STUFF((SELECT distinct ', CAST( MAX(CASE WHEN SrNo =' + CAST(SrNo AS VARCHAR(5)) +  ' THEN X END) AS VARCHAR(MAX)) '
            FROM T
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'');

SET @sqlY = STUFF((SELECT distinct ',CAST( MAX(CASE WHEN SrNo = ' + CAST(SrNo AS VARCHAR(5)) +  ' THEN Y END) AS VARCHAR(MAX)) '
            FROM T
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'');

set @sql = CONCAT('SELECT ''X'', ', @sqlX, ' 
                   FROM T
                   UNION ALL
                   SELECT ''Y'', ', @sqlY, '
                   FROM T');

execute(@sql)

sqlserver sqlfiddle

结果

    | X | MAX(CASE WHEN SrNo =1 THEN X END) | MAX(CASE WHEN SrNo =2 THEN X END) | MAX(CASE WHEN SrNo =3 THEN X END) | MAX(CASE WHEN SrNo =4 THEN X END) | MAX(CASE WHEN SrNo =5 THEN X END) | MAX(CASE WHEN SrNo =6 THEN X END) | MAX(CASE WHEN SrNo =7 THEN X END) |
    |---|-----------------------------------|-----------------------------------|-----------------------------------|-----------------------------------|-----------------------------------|-----------------------------------|-----------------------------------|
    | X |                                N1 |                                N2 |                                N3 |                                N4 |                                N5 |                                N6 |                                N7 |
    | Y |                               100 |                               200 |                               300 |                               400 |                               500 |                               600 |                               700 |

注意T 可以代替您的子查询或当前结果集。

【讨论】:

    【解决方案2】:

    Aaron Bertrand 写了一篇满足您需求的文章: https://www.mssqltips.com/sqlservertip/2783/script-to-create-dynamic-pivot-queries-in-sql-server/

    USE tempdb;
    GO
    CREATE TABLE dbo.Products
    (
      ProductID INT PRIMARY KEY,
      Name      NVARCHAR(255) NOT NULL UNIQUE
      /* other columns */
    );
    INSERT dbo.Products VALUES
    (1, N'foo'),
    (2, N'bar'),
    (3, N'kin');
    CREATE TABLE dbo.OrderDetails
    (
      OrderID INT,
      ProductID INT NOT NULL
        FOREIGN KEY REFERENCES dbo.Products(ProductID),
      Quantity INT
      /* other columns */
    );
    INSERT dbo.OrderDetails VALUES
    (1, 1, 1),
    (1, 2, 2),
    (2, 1, 1),
    (3, 3, 1);
    

    他的动态解决方案是在 PIVOT 语句中应用一个东西:

    编写一个收集列的子查询:

    DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX);
    SET @columns = N'';
    SELECT @columns += N', p.' + QUOTENAME(Name)
      FROM (SELECT p.Name FROM dbo.Products AS p
      INNER JOIN dbo.OrderDetails AS o
      ON p.ProductID = o.ProductID
      GROUP BY p.Name) AS x;
    

    然后创建你的可执行 SQL:

    SET @sql = N'
    SELECT ' + STUFF(@columns, 1, 2, '') + '
    FROM
    (
      SELECT p.Name, o.Quantity
       FROM dbo.Products AS p
       INNER JOIN dbo.OrderDetails AS o
       ON p.ProductID = o.ProductID
    ) AS j
    PIVOT
    (
      SUM(Quantity) FOR Name IN ('
      + STUFF(REPLACE(@columns, ', p.[', ',['), 1, 1, '')
      + ')
    ) AS p;';
    PRINT @sql;
    

    最后,运行它:

    EXEC sp_executesql @sql;
    

    【讨论】:

      猜你喜欢
      • 2018-12-31
      • 2017-08-07
      • 2011-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多