【问题标题】:How to create a table of name-value pairs in SQL如何在 SQL 中创建名称-值对表
【发布时间】:2020-10-12 12:27:12
【问题描述】:

使用SQL,如何转换这样的单行表...

Firstname Surname Address1        City   Country
--------- ------- --------------- ------ -------
Bob       Smith   101 High Street London UK

...到 name-value 对的表,如下所示:

Name      Value
--------- -------
Firstname   Bob
Surname     Smith
Address1    101 High Street
City        London
Country     UK

此脚本将创建原始表:

create table #OriginalTable (Firstname varchar(10), Surname varchar(10), 
Address1 varchar(50), City varchar(10), Country varchar(10))
insert into #OriginalTable 
select 
'Bob' Firstname, 
'Smith' Surname, 
'101 High Street' Address1, 
'London' City, 
'UK' Country

我正在寻求一种通用解决方案,它不依赖于列名始终是示例中的名称。

编辑: 我正在使用 SQL Server 2005。 我所追求的解决方案是将这些数据转换为名称-值对表的 SQL 脚本

回答: 使用我接受的答案作为答案,这就是我所使用的:

select   
result.Name, 
result.Value    
from   
  (select
    convert(sql_variant,FirstName) AS FirstName,
    convert(sql_variant,Surname) AS Surname,
    convert(sql_variant,Address1) AS Address1,
    convert(sql_variant,City) AS City,
    convert(sql_variant,Country) AS Country
    from #OriginalTable) OriginalTable
  UNPIVOT (Value For Name In (Firstname, Surname, Address1, City, Country)) as result

【问题讨论】:

标签: sql


【解决方案1】:

基本上你有两个问题 - 对于UNPIVOT,必须符合数据类型。另一个问题是列数未知。你想达到以下形式:

WITH    conformed
      AS ( SELECT   CONVERT(VARCHAR(255), [Firstname]) AS [Firstname],
                    CONVERT(VARCHAR(255), [Surname]) AS [Surname],
                    CONVERT(VARCHAR(255), [Address1]) AS [Address1],
                    CONVERT(VARCHAR(255), [City]) AS [City],
                    CONVERT(VARCHAR(255), [Country]) AS [Country]
           FROM     so1526080
         )
SELECT  ColumnKey,
        ColumnValue
FROM    conformed UNPIVOT ( ColumnValue FOR ColumnKey IN ( [Firstname], [Surname], [Address1], [City], [Country] ) ) AS unpvt

因此,使用元数据使用动态 SQL PIVOT(您可能需要使用 TABLE_SCHEMA 等解决此问题):

DECLARE @table_name AS SYSNAME
SET @table_name = 'so1526080'
DECLARE @conform_data_type AS VARCHAR(25)
SET @conform_data_type = 'VARCHAR(255)'

DECLARE @column_list AS VARCHAR(MAX)
DECLARE @conform_list AS VARCHAR(MAX)

SELECT  @conform_list = COALESCE(@conform_list + ', ', '') + 'CONVERT('
        + @conform_data_type + ', ' + QUOTENAME(COLUMN_NAME) + ') AS '
        + QUOTENAME(COLUMN_NAME),
        @column_list = COALESCE(@column_list + ', ', '')
        + QUOTENAME(COLUMN_NAME)
FROM    INFORMATION_SCHEMA.COLUMNS
WHERE   TABLE_NAME = @table_name

DECLARE @template AS VARCHAR(MAX)

SET @template = '
WITH    conformed
          AS ( SELECT  {@conform_list}
               FROM     {@table_name}
             )
    SELECT  ColumnKey,
            ColumnValue
    FROM    conformed UNPIVOT ( ColumnValue FOR ColumnKey IN ( {@column_list} ) ) AS unpvt
    '

DECLARE @sql AS VARCHAR(MAX)
SET @sql = REPLACE(REPLACE(REPLACE(@template, '{@conform_list}', @conform_list),
                           '{@column_list}', @column_list), '{@table_name}',
                   @table_name)    

PRINT @sql
EXEC ( @sql
    )

【讨论】:

    【解决方案2】:

    这是使用 JSON 的 MS SQL Server 解决方案。您不需要指定列名和数据类型。您需要做的就是在第 3 行指定表名和有效的 where 条件。

    DECLARE @TEMP TABLE (JSONHOLDER NVARCHAR(MAX));
    INSERT INTO @TEMP
    SELECT (SELECT * FROM YOURTABLE WHERE YOURID = 2589 FOR JSON AUTO) AS JSONHOLDER
    SELECT [KEY] as ColumnName, [VALUE] as ColumnValue FROM (SELECT [KEY] AS OLDKEY, [VALUE] AS OLDVALUE  FROM @TEMP A
    CROSS APPLY OPENJSON(A.JSONHOLDER)) B CROSS APPLY OPENJSON(B.OLDVALUE)
    

    【讨论】:

      【解决方案3】:

      这不是一个完整的解决方案,而是一个头脑风暴的想法,如果您将 information_schema.columns 与您的表交叉连接会怎样?

      SELECT column_name, OriginalTable.*
      FROM information_schema.columns 
      CROSS JOIN OriginalTable
      WHERE table_name = 'OriginalTable'
      AND /* PRIMARY KEY FILTER HERE*/
      

      【讨论】:

        【解决方案4】:

        通常使用应用程序代码在应用程序中进行透视是最有效的。数据透视并不是数据库的强项。

        【讨论】:

          【解决方案5】:

          使用两张桌子。一个表作为“keys”表,主表包含键表的 id 和值。

          然后,您也可以将 client_id 或其他内容添加到主表中,并在 client_idkey_id 上设置唯一键。

          【讨论】:

            【解决方案6】:

            这听起来像是自 2005 年以来 PIVOT 子句在 SQL Server 中可以做的事情(查找第一个示例),但您没有提及您使用的数据库引擎。

            【讨论】:

            • 我不知道你可以在不知道字段名称是什么的情况下进行 PIVOT。但如果可以,请发布 SQL
            • 对不起,我自己不使用 SQL Server,只在 Microsoft 文档中阅读。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-01-25
            • 2019-10-03
            • 1970-01-01
            • 2014-10-03
            • 1970-01-01
            • 2020-06-17
            相关资源
            最近更新 更多