假设我有一张桌子:
C1 C2 C3 C4
-- -- -- --
v11 v12 v13 v14
v21 v22 v23 v24
我希望输出为ColumnName和First Row映射,如下所示:
NC1 NC2
-- --
C1 v11
C2 v12
C3 v13
C4 v14
这个SQL查询是什么?
我需要动态地执行它 - 而不知道实际上我在表中有多少列!
答案 0 :(得分:2)
执行select 'C1' as nc1, c1 as nc2 from tablename where c1 = 'v11'
union all
select 'C2', c2 from tablename where c1 = 'v11'
union all
select 'C3', c3 from tablename where c1 = 'v11'
union all
select 'C4', c4 from tablename where c1 = 'v11'
:
ORDER BY nc1
也许您需要在最后添加witc cte as
(
select * from tablename where c1 = 'v11'
)
select 'C1' as nc1, c1 as nc2 from cte
union all
select 'C2', c2 from cte
union all
select 'C3', c3 from cte
union all
select 'C4', c4 from cte
。
公用表表达式版本:
type
答案 1 :(得分:2)
动态版本的更新:
CROSS APPLY
另一种方法是使用SELECT
x.NC1, x.NC2
FROM tbl t
CROSS APPLY ( VALUES
('C1', C1),
('C2', C2),
('C3', C3),
('C4', C4)
) x(NC1, NC2)
WHERE
t.C1 = 'V11'
。这样效率更高,因为它只扫描一次表:
author_lit| literature_id| title1 | title2
-------------------------------------------------------
--------------------------------------------------------
thomas | 1 | xxxxxxx | yyyyyyyy
------------------------------------------------------
-----------------------------------------------------------
Mr.xxx | 2 | xxxx | Yyyyy
-------------------------------------------------
---------------------------------------------
参考:An Alternative (Better?) Method to UNPIVOT (SQL Spackle) - SQLServerCentral
答案 2 :(得分:2)
根据具体情况,我会使用以下方法之一:
HKEY_CURRENT_USER\Control Panel\Colors
。
-- Source Table
IF EXISTS (SELECT * FROM sys.tables t WHERE t.schema_id = 1 AND t.name = N'SourceTable_83648326')
BEGIN
DROP TABLE dbo.SourceTable_83648326
END
SELECT *
INTO dbo.SourceTable_83648326
FROM (VALUES
('v11', 'v12', 'v13', 'v14'),
('v21', 'v22', 'v23', 'v24')
) SourceTable(C1, C2, C3, C4)
WHERE C1 = 'v11' -- It select required source row
-- Solution #1: dynamic query
DECLARE @Columns NVARCHAR(MAX) = N''
SELECT @Columns = @Columns + N', ' + QUOTENAME(c.name)
FROM sys.tables t JOIN sys.columns c ON t.object_id = c.object_id
WHERE t.schema_id = 1 -- dbo
AND t.name = N'SourceTable_83648326' -- Don't use ORDER BY or DISTINCT !
SET @Columns = STUFF(@Columns, 1, 2, '')
DECLARE @SqlStatement NVARCHAR(MAX) = N'
SELECT up.*
FROM (
SELECT *
FROM dbo.SourceTable_83648326
WHERE C1 = @p_C1 -- It select required source row
) ups -- UnPivot source
UNPIVOT( NC2_Value FOR NC1_ColumnType IN (' + @Columns + ') ) up -- UnPivot'
EXEC sp_executesql @SqlStatement, N'@p_C1 VARCHAR(50)', @p_C1 = 'v11' -- Replace with propper data type and max length
答案 3 :(得分:0)
另一种方式比UNION ALL& CROSS APPLY是使用UNPIVOT:
DECLARE @VarTable TABLE (C1 varchar(3), C2 varchar(3), C3 varchar(3), C4 varchar(3));
INSERT INTO @VarTable VALUES ('v11','v12','v13','v14');
INSERT INTO @VarTable VALUES ('v21','v22','v23','v24');
SELECT nc1, nc2
FROM (select * from @VarTable where c1 = 'v11') Q
UNPIVOT
(
nc2 for nc1 in (c1, c2, c3, c4)
) U
ORDER BY nc1, nc2;
但我实际上更喜欢Bogdan Sahlean的解决方案#2使用XML&交叉申请。
由于这是一个简洁的方法,不需要在查询中硬编码列名。
下面的查询是从他的回答中复制和修改的,只是为了用表变量测试它。
SELECT
X2.XmlCol.value('local-name(.)', 'varchar(8)') AS nc1,
X2.XmlCol.value('.', 'varchar(8)') AS nc2
FROM (
SELECT * FROM @VarTable
WHERE C1 = 'v11'
FOR XML RAW, TYPE
) X1(XmlCol)
CROSS APPLY X1.XmlCol.nodes(N'row/@*') X2(XmlCol);