0

我需要从 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任何帮助形成这个查询将不胜感激。

再次感谢!

4

1 回答 1

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 没有提供一种简单的方法来将字符串中的值提取到单独的元组中,这就是执行此操作的代码如此混乱的原因。

于 2013-07-11T22:28:13.520 回答