【问题标题】:MySQL export of single column showing duplicate entries only once单列的 MySQL 导出仅显示一次重复条目
【发布时间】:2013-07-12 06:42:21
【问题描述】:

我需要从 MySQL 数据库中导出单个列,每个条目只显示一次。所以在下表中:

id      author(s)               content
________________________________________
1       Bill, Sara, Mike        foo1             
1       Sara                    foo2
2       Bill, Sara, Mike        foo3   
2       Sara                    foo4
3       David                   foo5      
3       Mike                    foo5      

我需要将作者列表导出为“Bill, Sara, Mike, Susan”,以便每个姓名仅显示一次。

谢谢!

更新:我意识到这可能是不可能的,所以我将不得不接受一个导出的列表,它简单地消除了列中的任何精确重复项,因此输出将是这样的:Bill、Sara、Mike、Sara、David、Mike 任何帮助形成这个查询将不胜感激。

再次感谢!

【问题讨论】:

  • 呃。如果您仍然可以控制您的数据库结构,您应该将作者创建一个单独的表,并使用组合的主键/外键。例如,您将使用select distinct authorName from authors。是的,我不确定 MySQL 是否可以将您的列表分开。一种编程语言可能可以,但是……但即使可以,我认为您应该强制执行规则:1 个字段 = 1 个值。
  • 数据来自第三方,所以不幸的是我们被困在作者合并在一列中。

标签: mysql database export


【解决方案1】:

可以获得结果集,但我实际上只是将其转换为另一个表,每个作者一行。我不想从应用程序代码中运行这样的查询。

SUBSTRING_INDEX 函数可用于提取第一个、第二个池塘等。列表中的作者,例如

SUBSTRING_INDEX(SUBSTRING_INDEX(authors,',', 1 ),',',-1) AS author1
SUBSTRING_INDEX(SUBSTRING_INDEX(authors,',', 2 ),',',-1) AS author2
SUBSTRING_INDEX(SUBSTRING_INDEX(authors,',', 3 ),',',-1) AS author3

但这最后会变得一团糟,因为当您检索超出列表长度时,您会得到最后一位作者。

所以,你可以用一个相当难看的表达式来计算逗号的数量:

LENGTH(authors)-LENGTH(REPLACE(authors,',','')) AS count_commas

但是附加一个尾随逗号,然后将空字符串转换为 NULL 也同样简单 因此,将作者替换为:

CONCAT(authors,',')

然后将其包装在 TRIM 和 NULLIF 函数中。

NULLIF(TRIM( foo ),'')

然后,您可以编写一个从每一行获取第一作者的查询,另一个从每一行获取第二作者的查询(与第一个查询相同,只需将“1”更改为“2”,第三个作者等,直到列值中的最大作者数。将所有这些查询与 UNION 操作结合在一起(这将为您消除重复项。)

所以,这个查询:

SELECT NULLIF(TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(a.authors,','),',',1),',',-1)),'') AS author
  FROM unfortunately_designed_table a
 UNION
SELECT NULLIF(TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(a.authors,','),',',2),',',-1)),'')
  FROM unfortunately_designed_table a
 UNION
SELECT NULLIF(TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(a.authors,','),',',3),',',-1)),'')
  FROM unfortunately_designed_table a
 UNION
SELECT NULLIF(TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(a.authors,','),',',4),',',-1)),'')
  FROM unfortunately_designed_table a

这将返回唯一作者姓名的结果集(无疑是 NULL)。这只是获得列表中的前四位作者,您需要扩展它以获得第五位、第六位等。

您可以通过查找最大逗号数并加 1 来获得该列中的最大条目数

SELECT MAX(LENGTH(a.authors)-LENGTH(REPLACE(a.authors,',','')))+1 AS max_count
  FROM unfortunately_designed_table a

这让您知道您需要将上面的查询扩展多远才能获取所有作者值(在您运行查询的特定时间点......没有什么可以阻止某人将另一位作者添加到列中的列表中稍后。


在完成了在不同行上获取不同作者值的所有工作之后,您可能希望将它们留在这样的列表中。使用起来更容易。

当然,也可以将该结果集转换回以逗号分隔的列表,尽管返回的字符串的大小受max_allowed_packet 会话变量 (iirc) 的限制。

要将它作为单行返回,使用逗号分隔的列表,从上面获取整个查询,并将其包装在括号中作为行视图,给它一个别名,然后使用 GROUP_CONCAT 函数.

SELECT GROUP_CONCAT(d.author ORDER BY d.author) AS distinct_authors
  FROM (
         ...
       ) d
 WHERE d.author IS NOT NULL

如果您认为所有这些表达式都很丑陋,并且应该有更简单的方法来做到这一点,不幸的是(除了编写程序代码),真的没有。关系数据库旨在处理元组(行)中的信息,每一行代表一个实体。将多个实体或值填充到单个列中违背了关系设计。因此,SQL 没有提供一种简单的方法来将字符串中的值提取到单独的元组中,这就是执行此操作的代码如此混乱的原因。

【讨论】:

  • 谢谢斯宾塞,试一试。
猜你喜欢
  • 1970-01-01
  • 2011-01-02
  • 1970-01-01
  • 2021-03-24
  • 1970-01-01
  • 1970-01-01
  • 2012-09-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多