使用SQL,如何转换像这样的单行表...
Firstname Surname Address1 City Country
--------- ------- --------------- ------ -------
Bob Smith 101 High Street London UK
...到名称 - 值对的表中,如下所示:
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
答案 0 :(得分:6)
基本上你有两个问题 - 要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
)
答案 1 :(得分:0)
不是说它是一个完整的解决方案,而是一个头脑风暴的想法,如果你将information_schema.columns与你的桌子交叉加入怎么办?
SELECT column_name, OriginalTable.*
FROM information_schema.columns
CROSS JOIN OriginalTable
WHERE table_name = 'OriginalTable'
AND /* PRIMARY KEY FILTER HERE*/
答案 2 :(得分:0)
使用应用程序代码在应用程序中进行转动通常是最有效的。透视不一定是数据库的强项。
答案 3 :(得分:0)
使用两张桌子。一个表作为'keys'表,主表包含keys表的id以及值。
然后,您可以在主表中添加client_id等内容,并在client_id和key_id上设置唯一键。
答案 4 :(得分:0)
这是使用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)
答案 5 :(得分:-1)
这听起来像PIVOT子句自2005年以来在SQL Server中可以做的事情(查找第一个例子),但是你没有提到你使用的数据库引擎。