如何在 mysql 中拆分/取消透视 group_concat?
Posted
技术标签:
【中文标题】如何在 mysql 中拆分/取消透视 group_concat?【英文标题】:How to split / unpivot group_concat in mysql? 【发布时间】:2015-06-12 13:22:36 【问题描述】:我目前有一个视图,其中有一个名为 alt_email_contact 的列,我使用 group_concat 函数来获取与一个联系人关联的多封电子邮件。但是,我希望能够提取每封电子邮件并为每封电子邮件创建一个单独的列。
例子:
id email
1 SkyW@gmail.com, SW@gmail.com, WW@gmail.com, WalterW@gmail.com
电子邮件的数量可能会从一个用户更改为另一个用户,因此每个用户不会总是有四封电子邮件。我想为每封电子邮件创建一个新列,如下所示:
id email_1 email_2 email_3 email_4
1 SkyW@gmail.com SW@gmail.com WW@gmail.com WalterW@gmail.com
(我正在使用 phpmyadmin)我希望能够修改我的视图以包含每个用户的可变数量的电子邮件。
【问题讨论】:
你为什么要这样做?将每封备用电子邮件放在自己的行中有什么问题(即根本没有group_concat
)?这比拥有X
列数(在进行初始查询之前不知道X
)更具可扩展性。
SQL 查询具有固定数量的列。您想要多少封电子邮件?
@MikeBrant 我将这些字段导入另一个数据库,为此我必须将一个字段映射到另一个字段。因此,我需要与一个联系人关联的所有电子邮件都在一行中(并且每封电子邮件都在单独的列中)。
@GordonLinoff 我想要 5 封电子邮件,但可以少于 5 封
@dantheman 在目标数据库中,为什么需要将这些值全部放在一行中?你本质上试图做的不是关系数据库要做的事情。
【参考方案1】:
您可以使用substring_index()
来实现您想要的。它不是很漂亮,但它会起作用:
select id,
substring_index(emails, ', ', 1) as email_1
(case when length(emails) - length(replace(emails, ',', '')) >= 1
then substring_index(substring_index(emails, ', ', 2), ', ', -1)
end) as email_2,
(case when length(emails) - length(replace(emails, ',', '')) >= 2
then substring_index(substring_index(emails, ', ', 3), ', ', -1)
end) as email_3,
(case when length(emails) - length(replace(emails, ',', '')) >= 3
then substring_index(substring_index(emails, ', ', 4), ', ', -1)
end) as email_4,
(case when length(emails) - length(replace(emails, ',', '')) >= 4
then substring_index(substring_index(emails, ', ', 5), ', ', -1)
end) as email_5
from table t;
如果您愿意,可以将这些值插入到另一个表中。
【讨论】:
@GordonLiff,当我尝试实现这个查询时,它给了我重复,例如,如果一个联系人只有两封电子邮件,它将显示:email_1:w@gmail.com,email_2:ww @gmail.com,email_3:ww@gmail.com,email_4:ww@gmail.com,email_5:ww@gmail.com。我该如何解决这个问题? 对于输出的每一列,您需要更深地嵌套substring_index()
调用。
我总是需要 5 列。
@dantheman 。 . . when
比较中出现错误。【参考方案2】:
不要使用那个视图,因为GROUP_CONCAT()
已经破坏了规范化。您想使用 mysql 有限的 SQL 功能来模拟数据透视表。
假设您的视图基于如下所示的Contacts
表:
CREATE TABLE Contacts
( id INTEGER NOT NULL
, alt_email_contact VARCHAR(256) NOT NULL
);
改为创建这个帮助视图(基本上是 RANK() OVER (PARTITION BY id ORDER BY alt_email_contact)
,除了 MySQL 不支持 RANK()
):
CREATE VIEW NumberedContacts AS
SELECT c1.id, c1.alt_email_contact, COUNT(*) AS rank
FROM Contacts c1
INNER JOIN Contacts c2
ON c2.id = c1.id AND
c1.alt_email_contact >= c2.alt_email_contact
GROUP BY c1.id, c1.alt_email_contact;
然后您可以编写此查询或视图,它会为您提供最多 5 个备用电子邮件地址,按字母顺序排列:
CREATE VIEW ContactsForImport AS
SELECT c1.id
, c1.alt_email_contact AS email_1
, c2.alt_email_contact AS email_2
, c3.alt_email_contact AS email_3
, c4.alt_email_contact AS email_4
, c5.alt_email_contact AS email_5
FROM NumberedContacts AS c1
LEFT OUTER JOIN NumberedContacts AS c2
ON c1.id = c2.id AND c2.rank = 2
LEFT OUTER JOIN NumberedContacts AS c3
ON c1.id = c3.id AND c3.rank = 3
LEFT OUTER JOIN NumberedContacts AS c4
ON c1.id = c4.id AND c4.rank = 4
LEFT OUTER JOIN NumberedContacts AS c5
ON c1.id = c5.id AND c5.rank = 5
WHERE c1.rank = 1;
SQL Fiddle
【讨论】:
谢谢!这看起来正是我所需要的,但是有什么方法可以让我以与您选择视图相同的方式创建视图?我需要视图实际上具有与选择相同的结构。 不确定是什么问题。您可以使用CREATE VIEW ViewName AS SELECT …
对任何SELECT
进行查看。
啊好吧好吧!我不确定,因为这里有单独的语句。
可能有误传。 NumberedContacts
视图只是一个中间视图,用于构建您真正想要的视图。以上是关于如何在 mysql 中拆分/取消透视 group_concat?的主要内容,如果未能解决你的问题,请参考以下文章