如何在 SQL Server 中转置上三角矩阵

发布于 2024-10-16 22:00:15 字数 606 浏览 0 评论 0原文

如果我有一个表(上三角矩阵),数据类型是浮点型,例如:

columns_1  columns_2   columns_3   columns_4
     1            12          13          14  
  null             1          23          24   
  null          null           1          34   
  null          null        null           1       

我必须遵循什么方法才能获得以下结果?

    columns_1 columns_2 columns_3 columns_4
            1        12        13        14
           12         1        23        24
           13        23         1        34
           14        24        34         1

这在 SQL Server 2008 中可能吗?

If I have a table (upper triangular matrix), data types are float, an example like:

columns_1  columns_2   columns_3   columns_4
     1            12          13          14  
  null             1          23          24   
  null          null           1          34   
  null          null        null           1       

what approach do I have to follow to get the following?

    columns_1 columns_2 columns_3 columns_4
            1        12        13        14
           12         1        23        24
           13        23         1        34
           14        24        34         1

Is this possible in SQL server 2008?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

萌吟 2024-10-23 22:00:15

这是一种方法。

CREATE PROC dbo.Transpose @TableSchema sysname,
                          @TableName   sysname,
                          @Debug       bit = 0
AS

  DECLARE @N INT

  DECLARE @cols TABLE(
    idx INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
    col int NOT NULL )

  INSERT INTO @cols
  SELECT CAST(CASE WHEN COLUMN_NAME NOT LIKE '%[^0-9]%' THEN COLUMN_NAME END AS INT) AS col
  FROM   INFORMATION_SCHEMA.COLUMNS
  WHERE  TABLE_SCHEMA = @TableSchema
         AND TABLE_NAME = @TableName
         AND COLUMN_NAME NOT LIKE '%[^0-9]%'
  ORDER  BY col

  SET @N = @@ROWCOUNT

  IF @N = 0
      OR EXISTS(SELECT *
                FROM   @cols
                WHERE  idx <> col)
    BEGIN
        RAISERROR ('Incompatible table passed',16,1)
        RETURN
    END

  DECLARE @collist nvarchar(max)

  SELECT @collist = COALESCE(@collist + ',', '') + QUOTENAME(col)
  FROM   @cols  

DECLARE @dynsql nvarchar(max) = N'
WITH cte1
     AS (SELECT *,
                (SELECT ' + CAST(@N+1 AS VARCHAR(10)) + ' - COUNT(c)
                 FROM   (VALUES' + REPLACE(REPLACE(@collist,']','])'),'[','([') + ') T (c)) AS RN
         FROM   ' + QUOTENAME(@TableSchema) + '.' + QUOTENAME(@TableName) + '),
     cte2
     As (SELECT *
         FROM   cte1 UNPIVOT (data FOR col IN (' + @collist + ') ) AS unpvt),
     cte3
     As (SELECT RN,
                data,
                col
         FROM   cte2
         UNION ALL
         SELECT CAST(col as int),
                data,
                RN
         FROM   cte2)
SELECT ' + @collist + '
FROM   cte3 
PIVOT( max (data) FOR col IN (' + @collist + ')) AS pvt'

IF @Debug = 1
    SELECT @dynsql as [processing-instruction(x)] FOR XML PATH 

EXEC (@dynsql)

用法示例

CREATE TABLE dbo.BaseData(
  [1] float,
  [2] float,
  [3] float,
  [4] float)

INSERT INTO dbo.BaseData
SELECT 1,12,13,14 UNION ALL
SELECT NULL,1,23,24 UNION ALL 
SELECT NULL, NULL, 1,34 UNION ALL 
SELECT NULL, NULL, NULL, 1;

GO

EXEC dbo.Transpose 'dbo', 'BaseData', 0

Here's one way of doing it.

CREATE PROC dbo.Transpose @TableSchema sysname,
                          @TableName   sysname,
                          @Debug       bit = 0
AS

  DECLARE @N INT

  DECLARE @cols TABLE(
    idx INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
    col int NOT NULL )

  INSERT INTO @cols
  SELECT CAST(CASE WHEN COLUMN_NAME NOT LIKE '%[^0-9]%' THEN COLUMN_NAME END AS INT) AS col
  FROM   INFORMATION_SCHEMA.COLUMNS
  WHERE  TABLE_SCHEMA = @TableSchema
         AND TABLE_NAME = @TableName
         AND COLUMN_NAME NOT LIKE '%[^0-9]%'
  ORDER  BY col

  SET @N = @@ROWCOUNT

  IF @N = 0
      OR EXISTS(SELECT *
                FROM   @cols
                WHERE  idx <> col)
    BEGIN
        RAISERROR ('Incompatible table passed',16,1)
        RETURN
    END

  DECLARE @collist nvarchar(max)

  SELECT @collist = COALESCE(@collist + ',', '') + QUOTENAME(col)
  FROM   @cols  

DECLARE @dynsql nvarchar(max) = N'
WITH cte1
     AS (SELECT *,
                (SELECT ' + CAST(@N+1 AS VARCHAR(10)) + ' - COUNT(c)
                 FROM   (VALUES' + REPLACE(REPLACE(@collist,']','])'),'[','([') + ') T (c)) AS RN
         FROM   ' + QUOTENAME(@TableSchema) + '.' + QUOTENAME(@TableName) + '),
     cte2
     As (SELECT *
         FROM   cte1 UNPIVOT (data FOR col IN (' + @collist + ') ) AS unpvt),
     cte3
     As (SELECT RN,
                data,
                col
         FROM   cte2
         UNION ALL
         SELECT CAST(col as int),
                data,
                RN
         FROM   cte2)
SELECT ' + @collist + '
FROM   cte3 
PIVOT( max (data) FOR col IN (' + @collist + ')) AS pvt'

IF @Debug = 1
    SELECT @dynsql as [processing-instruction(x)] FOR XML PATH 

EXEC (@dynsql)

Example Usage

CREATE TABLE dbo.BaseData(
  [1] float,
  [2] float,
  [3] float,
  [4] float)

INSERT INTO dbo.BaseData
SELECT 1,12,13,14 UNION ALL
SELECT NULL,1,23,24 UNION ALL 
SELECT NULL, NULL, 1,34 UNION ALL 
SELECT NULL, NULL, NULL, 1;

GO

EXEC dbo.Transpose 'dbo', 'BaseData', 0
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文