如何以特定格式转置 SQL 中的表?

Posted

技术标签:

【中文标题】如何以特定格式转置 SQL 中的表?【英文标题】:How to transpose the table in SQL in a specific format? 【发布时间】:2018-09-25 04:49:43 【问题描述】:

我需要按以下格式转置 SQL 表。数据显示应先按日期分组,然后按时间分组,并显示与时间和日期对应的值。

发件人:

Datetime            | Value 1 | Value 2| Value 3
------------------------------------------------
2018-01-11 00:01:00 | 1.22    | 2.22   | 34.12
2018-01-11 00:02:00 | 2.22    | 3.22   | 43.12
2018-01-11 00:03:00 | 1.22    | 2.22   | 54.12
2018-01-11 23:58:00 | 1.22    | 2.22   | 34.12
2018-01-11 23:59:00 | 1.22    | 2.22   | 34.12

到:

         |    2018-01-11            |     2018-01-12           |
Time     | Value 1| Value 2| Value 3| Value 1| Value 2| Value 3|
----------------------------------------------------------------    
00:01:00 | 1.22   | 2.22   | 34.12  | 1.22   | 2.22   | 34.12  |
00:02:00 | 2.22   | 3.22   | 54.13  | 2.33   | 4.32   | 54.98  |
23:58:00 | 2.22   | 3.22   | 54.13  | 2.33   | 4.32  | 54.98   |
23:59:00 | 2.22   | 3.22   | 54.13  | 2.33   | 4.32  | 54.98   |

【问题讨论】:

这些列是否具有名称 datetime、value1 和 value2?您希望在列中保留多少天?任意数? 是的 @TomC 列名称是 datetime、value1、value2 和 value3。 @TomC 我需要显示 30 天,其中日期为列,时间为行 你用的是什么数据库? SQL 不适合这种情况。在您的应用程序中执行此操作。但无论如何,我们需要知道您使用的是哪种数据库产品。 “SQL”只是一种查询语言,所有关系数据库系统都使用它。请为您正在使用的数据库产品添加tag postgresql, oracle, sql-server, db2, ... 【参考方案1】:

这可以像这样在 sqlserver 中完成:它结合了动态数据透视表和临时表的创建。可能有更快的方法,但这可行。

首先创建示例数据:

create table #t(dt datetime, v1 decimal(5,2), v2 decimal(5,2), v3 decimal(5,2))
insert #t values 
('2018-01-11 00:01:00',1.22,2.22,34.12)
,('2018-01-11 00:02:00',2.22,3.22,43.12)
,('2018-01-11 00:03:00',1.22,2.22,54.12)
,('2018-01-11 23:58:00',1.22,2.22,34.12)
,('2018-01-11 23:59:00',1.22,2.22,34.12)
,('2018-01-12 00:01:00',1.55,5.55,34.15)
,('2018-01-12 00:02:00',5.55,3.55,43.15)
,('2018-01-12 00:03:00',1.55,5.55,54.15)
,('2018-01-12 23:58:00',1.55,5.55,34.15)
,('2018-01-12 23:59:00',1.55,5.55,34.15)

然后将列转置为行:

create table #t2(t varchar(5), dv varchar(13), v decimal(5,2))
insert #t2
select convert(varchar(5),convert(time,dt)) as t,
    convert(varchar(10),convert(date,dt))+' ' + v as dv,
    case when v='v1' then v1 when v='v2' then v2 when v='v3' then v3 end as v
from #t
cross join (values ('v1'),('v2'),('v3')) as v(v)

然后计算出列的列表(将日期和值组合成列名)

DECLARE @cols AS VARCHAR(MAX)

select @cols=STUFF((SELECT distinct ',' + QUOTENAME(dv) 
            FROM #t2 c
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

然后根据这些列创建一个动态查询

DECLARE @query AS VARCHAR(MAX);
set @query = 'SELECT t, ' + @cols + ' from 
            (
                select t, dv, v
                from #t2
           ) x
            pivot 
            (
                max(v)
                for dv in (' + @cols + ')
            ) p '

execute(@query) 

结果:(列实际上是对齐的!)

t   2018-01-11 v1   2018-01-11 v2   2018-01-11 v3   2018-01-12 v1   2018-01-12 v2   2018-01-12 v3
00:01   1.22    2.22    34.12   1.55    5.55    34.15
00:02   2.22    3.22    43.12   5.55    3.55    43.15
00:03   1.22    2.22    54.12   1.55    5.55    54.15
23:58   1.22    2.22    34.12   1.55    5.55    34.15
23:59   1.22    2.22    34.12   1.55    5.55    34.15

【讨论】:

以上是关于如何以特定格式转置 SQL 中的表?的主要内容,如果未能解决你的问题,请参考以下文章

有没有一种方法可以简单地转置 SQL 中的表。此表包含 Numeric 和 Varchar 值

如何以特定方式对我的数据框进行分组和转置?

如何在不使用数据透视的情况下将行转换或转置为 SQL 中的列?

oracle pl sql中如何将列数据转置为行

如何从 SQL Server 中特定数据库的表中获取所有列名?

如何转置给定的表?