quotename mysql_在MySQL中将行记录转换为列

这篇博客探讨了如何在MySQL中使用CASE...WHEN语句和聚合函数实现数据透视,以及如何处理动态列的情况。对于SQLServer,文章介绍了PIVOT函数和窗口函数的应用,提供了一个静态和动态SQL的示例,展示了如何更方便地进行数据转换。
摘要由CSDN通过智能技术生成

MySQL版本

您已经声明过尝试使用PIVOT,但是MySQL没有PIVOT函数.在MySQL中,您需要将聚合函数与条件逻辑语句(如CASE … WHEN或类似的东西)一起使用.您还需要旋转几个表和几个不同的列,这使事情变得有些复杂.似乎您还需要创建数量未知的新列,这增加了另一层复杂性.

如果您知道要在最终结果中显示的所有列,则可以轻松键入此查询的版本,如下所示:

select

p1.`SSN_ID`,

p1.Citizen_name,

p1.Company,

max(case when p2.Family_details = 'Spouse' then Family_members_name end) Spouse,

max(case when p2.Family_details = 'Child - 1' then Family_members_name end) Child1,

max(case when p2.Family_details = 'Child - 2' then Family_members_name end) Child2,

max(case when p2.Family_details = 'Child - 3' then Family_members_name end) Child3,

max(case when p2.Family_details = 'Child - 4' then Family_members_name end) Child4,

max(case when p3.Address_type = 'Present' then p3.Address end) PresentAddress,

max(case when p3.Address_type = 'Office' then p3.Address end) OfficeAddress,

max(case when p3.Address_type = 'Perement' then p3.Address end) PermAddress,

max(case when p3.PhoneNumber_type = 'Home' then p3.PhoneNumber end) HomePhone,

max(case when p3.PhoneNumber_type = 'Office' then p3.PhoneNumber end) OfficePhone,

max(case when p3.PhoneNumber_type = 'Fax' then p3.PhoneNumber end) FaxPhone

from Table_pivot_01 p1

left join Table_pivot_02 p2

on p1.`SSN_ID` = p2.`SSN_ID`

left join Table_pivot_03 p3

on p1.`SSN_ID` = p3.`SSN_ID`

group by p1.`SSN_ID`,

p1.Citizen_name,

p1.Company;

基本上,您在max(case …)语句中创建了一个新列,它将显示该值.如上所述,如果您想将未知值用作列,这会变得更加复杂.在MySQL中,您需要使用Prepared Statement,因此您可以使用动态SQL.您的代码看起来像这样:

SET @sql = NULL;

SET @sql1 = NULL;

SET @sql2 = NULL;

SET @sql3 = NULL;

SELECT

GROUP_CONCAT(DISTINCT

CONCAT(

' max(case when p2.Family_details = ''',

Family_details,

''' then Family_members_name end) AS `',

Family_details, '`'

)

) INTO @sql1

FROM Table_pivot_02;

SELECT

GROUP_CONCAT(DISTINCT

CONCAT(

' max(case when p3.Address_type = ''',

Address_type,

''' then Address end) AS `',

Address_type, '`'

)

) INTO @sql2

FROM Table_pivot_03;

SELECT

GROUP_CONCAT(DISTINCT

CONCAT(

' max(case when p3.PhoneNumber_type = ''',

PhoneNumber_type,

''' then PhoneNumber end) AS `',

PhoneNumber_type, '`'

)

) INTO @sql3

FROM Table_pivot_03

where PhoneNumber_type <> '';

SET @sql = CONCAT('SELECT p1.`SSN_ID`,

p1.Citizen_name,

p1.Company, ', @sql1, ',', @sql2, ',', @sql3, '

from Table_pivot_01 p1

left join Table_pivot_02 p2

on p1.`SSN_ID` = p2.`SSN_ID`

left join Table_pivot_03 p3

on p1.`SSN_ID` = p3.`SSN_ID`

group by p1.`SSN_ID`,

p1.Citizen_name,

p1.Company');

PREPARE stmt FROM @sql;

EXECUTE stmt;

DEALLOCATE PREPARE stmt;

在此过程中,您将创建一长串的max(case …)语句,将它们串联在一起,然后由数据库引擎执行.可能有更简单的方法来获得所需的结果,但这确实有效.在rextester上创建了一个演示以显示代码,这两者都会产生结果:

+-------+--------+--------------+---------+--------+------------+------------+------------+----------------------+----------------------+------------------------+------------------+--------------------+----------------+

| Row | SSN_ID | Citizen_name | Company | Spouse | Child - 1 | Child - 2 | Child - 3 | Present | Office | Perement | Home | Office | Fax |

+-------+--------+--------------+---------+--------+------------+------------+------------+----------------------+----------------------+------------------------+------------------+--------------------+----------------+

| 1 | 12345 | John | XYZ | Mari | John Jr. 1 | John Jr. 2 | NULL | Address_John_Present | Address_John_Office | Address_John_Perement | John_Home_phone | John_Office_phone | John_FAX_phone |

| 2 | 12346 | Tom | ABC | Ken | NULL | NULL | NULL | Address_Tom_Present | Address_Tom_Office | NULL | Tom_Home_phone | Tom_Office_phone | NULL |

| 3 | 12347 | Jerry | QWER | Suzen | Jerry Jr.1 | Jerry Jr.2 | Jerry Jr.3 | NULL | Address_Jerry_Office | Address_Jerry_Perement | Jerry_Home_phone | Jerry_Office_phone | NULL |

| 4 | 12348 | Joe | PQR | NULL | Joe Jr.1 | Joe Jr.2 | NULL | Address_Joe_Present | Address_Joe_Office | Address_Josh_Perement | Joe_Home_phone | Joe_Office_phone | NULL |

| 5 | 12349 | Josh | NULL | Zoe | Josh Jr.1 | Josh Jr.2 | NULL | Address_Josh_Present | NULL | Address_Josh_Perement | Josh_Home_phone | NULL | Josh_FAX_phone |

+-------+--------+--------------+---------+--------+------------+------------+------------+----------------------+----------------------+------------------------+------------------+--------------------+----------------+

根据您的评论(每个人可能有多个电话号码类型),您需要创建row number for each group of phone types.不幸的是,MySQL又没有窗口功能,因此您需要使用用户定义的变量来获取最终的结果.当查询PhoneNumber_type时,您将需要使用类似以下的内容:

select *

from

(

select SSN_ID, PhoneNumber_type, PhoneNumber,

@num:= case when @group = SSN_ID and @type = PhoneNumber_type then @num +1 else if(@group := SSN_ID, 1, 1) end rn,

@group:= SSN_ID,

@type:=PhoneNumber_type

from Table_pivot_03 t

CROSS JOIN (select @num:=0, @group:=null, @type:=null) c

where t.PhoneNumber_type <> ''

order by SSN_ID, PhoneNumber_type

) as x;

这将为每个用户和电话类型创建一个行号值.然后将其集成到动态SQL代码中:

SET @sql = NULL;

SET @sql1 = NULL;

SET @sql2 = NULL;

SET @sql3 = NULL;

SELECT

GROUP_CONCAT(DISTINCT

CONCAT(

' max(case when p2.Family_details = ''',

Family_details,

''' then Family_members_name end) AS `',

Family_details, '`'

)

) INTO @sql1

FROM Table_pivot_02;

SELECT

GROUP_CONCAT(DISTINCT

CONCAT(

' max(case when p3.Address_type = ''',

Address_type,

''' then Address end) AS `',

Address_type, '`'

)

) INTO @sql2

FROM Table_pivot_03;

SELECT

GROUP_CONCAT(DISTINCT

CONCAT(

' max(case when p.PhoneNumber_type = ''',

PhoneNumber_type,

''' and rn = ', rn, ' then p.PhoneNumber end) AS `',

PhoneNumber_type, rn, '`'

)

) INTO @sql3

FROM

(

select SSN_ID, PhoneNumber_type, PhoneNumber,

@num:= case when @group = SSN_ID and @type = PhoneNumber_type then @num +1 else if(@group := SSN_ID, 1, 1) end rn,

@group:= SSN_ID,

@type:=PhoneNumber_type

from Table_pivot_03 t

CROSS JOIN (select @num:=0, @group:=null, @type:=null) c

where t.PhoneNumber_type <> ''

order by SSN_ID, PhoneNumber_type

) as x;

SET @sql = CONCAT('SELECT p1.`SSN_ID`,

p1.Citizen_name,

p1.Company, ', @sql1, ',', @sql2, ',', @sql3, '

from Table_pivot_01 p1

left join Table_pivot_02 p2

on p1.`SSN_ID` = p2.`SSN_ID`

left join Table_pivot_03 p3

on p1.SSN_ID = p3.SSN_Id

left join

(

select SSN_ID, PhoneNumber_type, PhoneNumber,

@num:= case when @group = SSN_ID and @type = PhoneNumber_type then @num +1 else if(@group := SSN_ID, 1, 1) end rn,

@group:= SSN_ID,

@type:=PhoneNumber_type

from Table_pivot_03 t

CROSS JOIN (select @num:=0, @group:=null, @type:=null) c

where t.PhoneNumber_type <> ''''

order by SSN_ID, PhoneNumber_type

) as p

on p1.SSN_ID = p.SSN_Id

group by p1.`SSN_ID`,

p1.Citizen_name,

p1.Company');

#select @sql;

PREPARE stmt FROM @sql;

EXECUTE stmt;

DEALLOCATE PREPARE stmt;

参见另一个demo.

SQL Server版本

既然您已经说过需要SQL Server版本,那么这里就是该版本. SQL Server具有一些使操作变得更加容易的功能,包括PIVOT函数,UNPIVOT函数以及诸如row_number之类的窗口函数.这是查询的静态版本,其中只列出了几列:

select SSN_ID,

Citizen_name,

Company,

Spouse, [Child - 1], [Child - 2], [Child - 3], [Child - 4]

from

(

select SSN_ID,

Citizen_name,

Company,

col,

value

from

(

select

p1.SSN_ID,

p1.Citizen_name,

p1.Company,

p2.Family_details,

p2.Family_members_name,

p3.Address_type,

p3.Address,

PhoneNumber_type = p.PhoneNumber_type + cast(p.rn as varchar(10)),

p.PhoneNumber

from Table_pivot_01 p1

left join Table_pivot_02 p2

on p1.SSN_ID = p2.SSN_ID

left join Table_pivot_03 p3

on p1.SSN_ID = p3.SSN_ID

left join

(

select SSN_ID, PhoneNumber_type, PhoneNumber,

rn = row_number() over(partition by SSN_ID, PhoneNumber_type order by SSN_ID, PhoneNumber_type)

from Table_pivot_03

where PhoneNumber_type <> ''

) p

on p1.SSN_ID = p.SSN_ID

) d

cross apply

(

select 'Family_details', Family_details, Family_members_name union all

select 'Address_type', Address_type, Address union all

select 'PhoneNumber_type', PhoneNumber_type, PhoneNumber

) c(orig, col, value)

) src

pivot

(

max(value)

for col in (Spouse, [Child - 1], [Child - 2], [Child - 3], [Child - 4])

) piv

然后,如果您需要动态sql版本,则代码如下所示:

DECLARE @cols AS NVARCHAR(MAX),

@query AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(Col)

from

(

select col, ord

from

(

select

p1.SSN_ID,

p1.Citizen_name,

p1.Company,

p2.Family_details,

p2.Family_members_name,

p3.Address_type,

p3.Address,

PhoneNumber_type = p.PhoneNumber_type + cast(p.rn as varchar(10)),

p.PhoneNumber

from Table_pivot_01 p1

left join Table_pivot_02 p2

on p1.SSN_ID = p2.SSN_ID

left join Table_pivot_03 p3

on p1.SSN_ID = p3.SSN_ID

left join

(

select SSN_ID, PhoneNumber_type, PhoneNumber,

rn = row_number() over(partition by SSN_ID, PhoneNumber_type order by SSN_ID, PhoneNumber_type)

from Table_pivot_03

where PhoneNumber_type <> ''

) p

on p1.SSN_ID = p.SSN_ID

) d

cross apply

(

select 'Family_details', Family_details, Family_members_name, 1 union all

select 'Address_type', Address_type, Address, 2 union all

select 'PhoneNumber_type', PhoneNumber_type, PhoneNumber, 3

) c(orig, col, value, ord)

) d

group by col, ord

order by ord, col

FOR XML PATH(''), TYPE

).value('.', 'NVARCHAR(MAX)') ,1,1,'');

set @query = N'SELECT ' + @cols + N' from

(

select SSN_ID,

Citizen_name,

Company,

col,

value

from

(

select

p1.SSN_ID,

p1.Citizen_name,

p1.Company,

p2.Family_details,

p2.Family_members_name,

p3.Address_type,

p3.Address,

PhoneNumber_type = p.PhoneNumber_type + cast(p.rn as varchar(10)),

p.PhoneNumber

from Table_pivot_01 p1

left join Table_pivot_02 p2

on p1.SSN_ID = p2.SSN_ID

left join Table_pivot_03 p3

on p1.SSN_ID = p3.SSN_ID

left join

(

select SSN_ID, PhoneNumber_type, PhoneNumber,

rn = row_number() over(partition by SSN_ID, PhoneNumber_type order by SSN_ID, PhoneNumber_type)

from Table_pivot_03

where PhoneNumber_type <> ''''

) p

on p1.SSN_ID = p.SSN_ID

) d

cross apply

(

select ''Family_details'', Family_details, Family_members_name union all

select ''Address_type'', Address_type, Address union all

select ''PhoneNumber_type'', PhoneNumber_type, PhoneNumber

) c(orig, col, value)

) src

pivot

(

max(value)

for col in (' + @cols + N')

) p '

exec sp_executesql @query;

这是另一个demo.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值