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

3
如果我有一个表格(上三角矩阵),数据类型为浮点数,例如:
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中是否可能实现这一点?

有一个给定的固定列和行数?这些包含混合单词和数字的列是什么数据类型? - Martin Smith
好的,数据类型是浮点数,矩阵(表)的维度已知。 - edgarmtze
顺便提一下,这里有一个与你的问题相关但不同的问题(链接:http://stackoverflow.com/questions/3505978/triangular-multiplication-matrix-generation/3509076#3509076)。它可能会给你一些进一步的想法。 - Martin Smith
1个回答

2
这是一种实现方法。
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

请问,您如何使用动态SQL来通用地处理任何表大小的数据? - edgarmtze
@darkcminor - 是的,必须这样做。在SQL Server中,没有办法处理动态列而不使用动态SQL。我回答中的示例仅适用于最大为9 * 9的矩阵,因为它查找单个数字列名后缀,因此您还需要进行相应的调整。您的矩阵可能有多大? - Martin Smith
矩阵的尺寸可能是100x100甚至更大......你的例子非常好,你有什么建议? - edgarmtze
当你进行基本表的选择SELECT 1,12,13,14 union all...时,它如何变得动态???你如何选择每一行? - edgarmtze
@darkcminor - 你显然会完全省略 @BaseData 的内容,并将其替换为实际表的名称。它不需要是一个表变量,这只是为了演示目的。还有几个要点。仅包含 float 列的表中列的绝对最大数量为991。此外,我并不确定 SQL Server 是执行此操作的正确位置,但我很乐意给你一些代码来尝试! - Martin Smith
好的@Martin,我会尝试用你宝贵的代码解决问题,我相信我会继续提问,谢谢。 - edgarmtze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接