以“列标题:列值”格式获取单个记录的 SQL 查询

Posted

技术标签:

【中文标题】以“列标题:列值”格式获取单个记录的 SQL 查询【英文标题】:SQL query for fetching a single record in format "column heading: column value" 【发布时间】:2012-12-12 13:04:17 【问题描述】:

假设我有这张桌子:

Create table test(a int, b int, c int, d int)

我可以简单地写'select * from test'来获得以下第一条记录:

A B C D 1 2 3 4

但是,我想要这样(单条记录四行):

答:1 乙:2 C: 3 D: 4

有人可以帮我做这件事吗?

这是在远程桌面系统上查看单个记录所必需的,该系统非常慢,水平滚动很糟糕,其中有 800 列。所以我需要从一条记录中查看数据的格式。

【问题讨论】:

取决于您使用的 SQL 工具(客户端)。有些人可以直接这样做。 我有sql server management studio 2008 我假设您的表中有多行?如果是这样,那么您会期望将扩展行数乘以查询中涉及的列数,对吗?此外,您希望结果是真正的行,而不仅仅是带有(比如说)换行符的行? 我只需要一条记录中的数据。不是全部。 【参考方案1】:

您可以使用UNPIVOT 函数来执行此操作,以下版本将列名和值连接在一起,但您始终可以将它们显示为单独的列:

select col+':'+cast(value as varchar(10)) col
from test
unpivot
(
  value
  for col in (A, B, C, D)
) unpiv

见SQL Fiddle with Demo

如果您有已知数量的列,上述方法非常有用,但如果您有 800 列要转换,您可能需要使用动态 sql 来执行此操作:

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('test')
         for xml path('')), 1, 1, '')

set @query 
  = 'select col+'':''+cast(value as varchar(10)) col
     from test
     unpivot
     (
       value
       for col in ('+ @colsunpivot +')
     ) u'

exec(@query)

见SQL Fiddle with Demo

注意:当使用UNPIVOT 时,所有需要转换的列的数据类型必须相同。因此,您可能需要根据需要转换/转换数据。

编辑#1,由于所有列上的数据类型都不同,并且您需要取消透视它们,因此您可以使用以下代码。

第一部分获取要动态取消透视的列列表:

select @colsUnpivot = stuff((select ','+quotename(C.name)
             from sys.columns as C
             where C.object_id = object_id('test')
             for xml path('')), 1, 1, '')

第二部分获得相同的列列表,但将每一列包装在 cast 中作为 varchar

select @colsUnpivotCast = stuff((select ', cast('+quotename(C.name)+' as varchar(50)) as '+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('test')
         for xml path('')), 1, 1, '')

那么您的最终查询将是:

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @colsUnpivotCast AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)


select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('test')
         for xml path('')), 1, 1, '')

select @colsUnpivotCast = stuff((select ', cast('+quotename(C.name)+' as varchar(50)) as '+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('test')
         for xml path('')), 1, 1, '')


set @query 
  = 'select col+'':''+value col
     from
    (
      select '+@colsUnpivotCast+'
      from test
    ) src
     unpivot
     (
       value
       for col in ('+ @colsunpivot +')
     ) u'


exec(@query)

见SQL Fiddle with Demo

UNPIVOT 函数正在执行与 UNION ALL 相同的过程,如下所示:

select col+':'+value as col
from
(
  select A value, 'A' col
  from test
  union all
  select cast(B as varchar(10)) value, 'B' col
  from test
  union all
  select cast(C as varchar(10)) value, 'C' col
  from test
  union all
  select cast(D as varchar(10)) value, 'D' col
  from test
) src

见SQL Fiddle with Demo

所有查询的结果都是一样的:

|    COL |
----------
|    A:1 |
| B:2.00 |
|    C:3 |
|    D:4 |

编辑 #2: 使用 UNPIVOT 去除任何可能导致某些数据丢失的空列。如果是这种情况,那么您将需要用 IsNull() 包装列以替换 null 值:

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @colsUnpivotCast AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)


select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('test')
         for xml path('')), 1, 1, '')

select @colsUnpivotCast = stuff((select ', IsNull(cast('+quotename(C.name)+' as varchar(50)), '''') as '+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('test')
         for xml path('')), 1, 1, '')


set @query 
  = 'select col+'':''+value col
     from
    (
      select '+@colsUnpivotCast+'
      from test
    ) src
     unpivot
     (
       value
       for col in ('+ @colsunpivot +')
     ) u'


exec(@query)

见SQL Fiddle with Demo

替换空值,将得到如下结果:

|    COL |
----------
|    A:1 |
| B:2.00 |
|     C: |
|    D:4 |

【讨论】:

我需要像这样在 unpivot 子句中写下所有 800 列吗? @puretechy 我刚刚也用动态版本编辑了这个。 我需要使用强制转换的地方,有800列,我需要全部转换成nvarchar。你不是已经在这里使用演员了吗?我从未使用过 PIVOT,现在无法理解这一点。 如何将所有内容都转换为 VARCHAR ?收到此错误 - “列“USR_USER_ID”的类型与 UNPIVOT 列表中指定的其他列的类型冲突。” 每列的数据类型是否不同?

以上是关于以“列标题:列值”格式获取单个记录的 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

如何设置子查询以获取具有最新日期和最大 ID 的单个记录?

SQL Server 查询以根据用户提供的 id 获取嵌套的子记录

如何使用休眠本机查询获取单个记录字符串值?

如何使用已定义的表获取我所需的记录

怎么用sql语句获取每一组的第一条记录(包括所有字段,不是单个字段)

SQL 查询以获取该用户的最新记录