具有列名和第一行值的Sql映射

具有列名和第一行值的Sql映射,sql,sql-server,Sql,Sql Server,假设我有一张桌子: C1 C2 C3 C4 -- -- -- -- v11 v12 v13 v14 v21 v22 v23 v24 我希望输出为ColumnName和第一行映射,如下所示: NC1 NC2 -- -- C1 v11 C2 v12 C3 v13 C4 v14 对此的SQL查询是什么 我需要动态地做这件事——

假设我有一张桌子:

C1   C2   C3   C4
--   --   --   --
v11  v12  v13  v14
v21  v22  v23  v24
我希望输出为ColumnName和第一行映射,如下所示:

        NC1   NC2
        --    --  
        C1    v11 
        C2    v12 
        C3    v13
        C4    v14
对此的SQL查询是什么

我需要动态地做这件事——而不知道我在表中有多少列

执行联合所有:

也许您需要在末尾添加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
做一个工会:

也许您需要在末尾添加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

动态版本的更新:

DECLARE @sql NVARCHAR(MAX) = '';

SELECT @sql = 
'SELECT
    x.NC1, x.NC2
FROM tbl t
CROSS APPLY ( VALUES ' +
(SELECT STUFF((
    SELECT ',(''' +COLUMN_NAME + ''', ' + QUOTENAME(COLUMN_NAME) + ')'
    FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'Tbl'            
    FOR XML PATH('')
), 1, 1, '')) +
') x (NC1, NC2)
WHERE
    t.C1 = ''V11''';

PRINT (@sql);
EXEC (@sql);
另一种方法是使用交叉应用。这更有效,因为它只扫描表一次:

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'

参考:

动态版本的更新:

DECLARE @sql NVARCHAR(MAX) = '';

SELECT @sql = 
'SELECT
    x.NC1, x.NC2
FROM tbl t
CROSS APPLY ( VALUES ' +
(SELECT STUFF((
    SELECT ',(''' +COLUMN_NAME + ''', ' + QUOTENAME(COLUMN_NAME) + ')'
    FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'Tbl'            
    FOR XML PATH('')
), 1, 1, '')) +
') x (NC1, NC2)
WHERE
    t.C1 = ''V11''';

PRINT (@sql);
EXEC (@sql);
另一种方法是使用交叉应用。这更有效,因为它只扫描表一次:

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'

参考资料:

根据上下文,我将使用以下解决方案之一:

-- 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


根据上下文,我将使用以下解决方案之一:

-- 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


第二排呢?我不需要第二排。假设我只想映射第一行,其中C1='v11',那么第二行呢?我不需要第二行。假设我只想映射第一行,其中C1='v11'谢谢。我需要在不知道表中有多少列的情况下动态地执行它。谢谢。我需要在不知道表中有多少列的情况下动态地执行它。我真的需要学习那些奇特的SQL Server函数。向上投票!谢谢我需要在不知道表中有多少列的情况下动态地执行它。我真的需要学习那些奇特的SQL Server函数。向上投票!谢谢我需要在不知道表中实际有多少列的情况下动态执行此操作。下面的XPath返回行元素中的所有*attributes@:row/@*。我已经完成了您的solution1动态查询。我遇到的唯一问题是,F13列的类型与UNPIVOT列表中指定的其他列的类型冲突。F13列的数据类型为ntext。有什么方法可以解决这个问题吗?来自dbo.SourceTable83648326的SELECT*的SELECT子句应该包括具有兼容数据类型的列。最简单的解决方案是将所有值转换为相同的数据类型ex.[N]VARCHAR或INT:选择CONVERTVARCHAR,C1作为C1。。。。如果它不起作用,那么您应该为SourceTable提供创建表脚本。以下XPath从行元素返回所有*attributes@:row/@*。我遇到的唯一问题是,F13列的类型与UNPIVOT列表中指定的其他列的类型冲突。F13列的数据类型为ntext。有什么方法可以解决这个问题吗?来自dbo.SourceTable83648326的SELECT*的SELECT子句应该包括具有兼容数据类型的列。最简单的解决方案是将所有值转换为相同的数据类型ex.[N]VARCHAR或INT:选择CONVERTVARCHAR,C1作为C1。。。。如果它不起作用,那么您应该为SourceTable提供创建表脚本。。。。