【问题标题】:How to count items in comma separated list MySQL如何计算逗号分隔列表 MySQL 中的项目
【发布时间】:2011-08-11 01:57:41
【问题描述】:

所以我的问题很简单:

我在 SQL 中有一个以逗号分隔的列表(即cats,dogs,cows,)我需要使用 only sql 计算其中的项目数(所以无论我的函数是什么(让我们调用它现在的效果)会像这样工作:

 SELECT fx(fooCommaDelimColumn) AS listCount FROM table WHERE id=...

我知道这是有缺陷的,但你明白了(顺便说一句,如果 fooCommaDelimColumn 的值是 cats,dogs,cows,,那么 listCount 应该返回 4...)。

仅此而已。

【问题讨论】:

  • 这个话题也被here回复了

标签: mysql sql


【解决方案1】:

没有内置函数可以计算字符串中子字符串的出现次数,但是您可以计算原始字符串与不带逗号的相同字符串之间的差异:

LENGTH(fooCommaDelimColumn) - LENGTH(REPLACE(fooCommaDelimColumn, ',', ''))

它在近 8 年的时间里被多次编辑(哇!),所以为了清楚起见:上面的查询不需要 + 1,因为 OPs 数据有一个额外的尾随逗号。

虽然确实,对于看起来像这样的字符串,一般情况下:foo,bar,baz 正确的表达式应该是

LENGTH(col) - LENGTH(REPLACE(col, ',', '')) + 1

【讨论】:

  • 虽然这行得通,但如果 Tomas 正确地建模了 is 数据库,他可能不会有这个问题。
  • 实际上,如果列表中只有一项,您应该在答案中加 1:LENGTH(fooCommaDelimColumn) - LENGTH(REPLACE(fooCommaDelimColumn, ',', '')) + 1。这个对于所表达的原则,仍然值得 +1。
  • @RolandoMySQLDBA:我也是这么想的,但是 Tomas 的字符串包含一个尾随逗号,所以不需要。
  • +1+♡ 太棒了。出于好奇,是否有一种方法可以在不提前知道每行是否有尾随逗号的情况下正确计数?我知道,不是我的问题,但我只是好奇。 :)
  • @Alvaro Joao:你说得对,它通常应该有 + 1,但在这种特殊情况下,OP 列表有一个额外的尾随逗号。
【解决方案2】:

遵循@zerkms 的建议。

如果您不知道是否有尾随逗号,请使用 TRIM 功能删除任何尾随逗号:

(
    LENGTH(TRIM(BOTH ',' FROM fooCommaDelimColumn))
  - LENGTH(REPLACE(TRIM(BOTH ',' FROM fooCommaDelimColumn), ',', ''))
  + 1
) as count

参考:http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_trim

我也同意重构表是最好的选择,但如果现在不可能,这个 sn-p 可以完成这项工作。

【讨论】:

  • 这是全方位的解决方案。有时需要以 JSON 编码的形式(例如 ["ABC","DEF","GHI","JKL"])存储数据(数组),但还需要计算其中的项目。为此,即使没有修剪,您的解决方案也能正常工作。
【解决方案3】:

zerkms 的解决方案有效,这一点毫无疑问。但是正如 Steve Wellens 指出的那样,您的问题是由不正确的数据库模式造成的。一个列中不应有多个值,因为它违反了第一条正常定律。相反,您应该至少制作两张桌子。例如,假设您有 成员,他们拥有 animals

table member (member_id, member_name)
table member_animal (member_id, animal_name)

更好的是:由于许多用户可以拥有相同类型的动物,您应该创建 3 个表:

table member (member_id, member_name)
table animal (animal_id, animal_name)
table member_animal (member_id, animal_id)

您可以像这样填充您的表格,例如:

member (1, 'Tomas')
member (2, 'Vincent')
animal (1, 'cat')
animal (2, 'dog')
animal (3, 'turtle')
member_animal (1, 1)
member_animal (1, 3)
member_animal (2, 2)
member_animal (2, 3)

而且,为了回答你最初的问题,如果你想知道每个用户有多少只动物,你会这样做:

SELECT member_id, COUNT(*) AS num_animals
FROM member
INNER JOIN member_animal
    USING (member_id)
INNER JOIN animal
    USING (animal_id)
GROUP BY member_id;

【讨论】:

  • 确实这个答案更正确。在 SO,我们将互相帮助以正确的方式实施,解决问题的根源,+1
  • 感谢您的帮助,不过我仍然很想获得一些学习资源(您可以看到我的 sql 知识以 UPDATE 结尾:))
  • 在数据库设计中仍然存在一些情况,其中常见的规范化规则不是优先级。例如当大型表中的连接速度是最重要的因素时,允许例外是合法的,并且将 csv 放在 varchar 字段中是绝对好的和最佳实践。因此可以以闪电般的速度检索值,并且可以避免复杂的连接(如文森特答案所示)。只是想指出这一点。
【解决方案4】:

如果我们做 +1 并且如果我们有一个空列,它总是作为 1 使其成为 0,我们可以在 mySQL 中使用 IF 条件。

IF(LENGTH(column_name) > 0, LENGTH(column_name) - LENGTH(REPLACE(column_name, ',', '')) + 1, 0)

【讨论】:

    【解决方案5】:

    答案是更正数据库架构。这听起来像是一个需要连接表的多对多关系。 http://en.wikipedia.org/wiki/Junction_table

    【讨论】:

      【解决方案6】:

      此版本不支持前导或尾随逗号,但支持计数为 0 的空值:

      IF(values, LENGTH(values) - LENGTH(REPLACE(values, ',', '')) + 1, 0) AS values_count
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多