sqlite3 JOIN,GROUP_CONCAT 使用不同的自定义分隔符
Posted
技术标签:
【中文标题】sqlite3 JOIN,GROUP_CONCAT 使用不同的自定义分隔符【英文标题】:sqlite3 JOIN, GROUP_CONCAT using distinct with custom separator 【发布时间】:2012-11-03 04:29:33 【问题描述】:给定一个“事件”表,其中每个事件可能与零个或多个“演讲者”和零个或多个“术语”相关联,那些通过连接表与事件关联的记录,我需要生成一个所有事件的表每行有一列代表与每个事件关联的“speaker_names”和“term_names”列表。
但是,当我运行查询时,speaker_names 和 term_names 值存在重复,因为连接表会为每个发言人和事件的术语在每个关联中生成一行:
1|Soccer|Bobby|Ball
2|Baseball|Bobby - Bobby - Bobby|Ball - Bat - Helmets
3|Football|Bobby - Jane - Bobby - Jane|Ball - Ball - Helmets - Helmets
group_concat 聚合函数能够使用“distinct”,它消除了重复,但遗憾的是它不支持我真正需要的自定义分隔符。我得到了这些结果:
1|Soccer|Bobby|Ball
2|Baseball|Bobby|Ball,Bat,Helmets
3|Football|Bobby,Jane|Ball,Helmets
我的问题是:有没有一种方法可以形成查询或更改数据结构以获得我想要的结果?
请记住,这是我需要的 sqlite3 查询,我无法添加自定义 C 聚合函数,因为这是用于 android 部署。
我创建了一个要点,让您可以轻松地测试可能的解决方案:https://gist.github.com/4072840
【问题讨论】:
【参考方案1】:有一种特殊情况在 sqlite 中不起作用:group_concat(DISTINCT X, Y)
而在 SQL 中,您可以在 sqlite 中使用 group_concat(DISTINCT X SEPARATOR Y)
,但您不能
这个例子:Select group_concat(DISTINCT column1, '|') from example_table group by column2;
给出结果:DISTINCT 聚合必须只有一个参数在第 1 行:
解决办法:
select rtrim(replace(group_concat(DISTINCT column1||'@!'), '@!,', '|'),'@!') from example_table
【讨论】:
【参考方案2】:只是为了提出一个适当的解决方法(murb 的答案奇怪地用括号括起来)。
问题:
group_concat(distinct column_name, 'custom_separator')
将custom_separator
作为distinct
的一部分。
解决方案:
我们需要一些无操作让 SQLite 知道 distinct
完成(包装 distinct 和它的参数)。
No-op 可以替换为空字符串作为第二个参数 (documentation to replace)。
group_concat(replace(distinct column_name, '', ''), 'custom_separator')
编辑:
刚刚发现它不起作用:-( - 可以调用但distinct
不再起作用了
【讨论】:
【参考方案3】:问题只出现在 group_concat(X,Y) 表达式,而不是 group_concat(X) 表达式。
group_concat(distinct X) 效果很好。
所以,如果 ',' 对你有好处,那没有问题,但如果你想要一个 ';'而不是 ',' (并且您确定原始文本中没有 ',')您可以这样做:
replace(group_concat(distinct X), ',', ';')
【讨论】:
【参考方案4】:我也遇到过这个问题,但想出了一个我觉得更容易理解的方法。由于 SQLite 报告了SQLite3::SQLException: DISTINCT aggregates must have exactly one argument
,因此问题似乎与GROUP_CONCAT
方法无关,而是在GROUP_CONCAT
中使用DISTINCT
...
当您将 DISTINCT“子查询”封装在实际上什么都不做的 REPLACE
方法中时,您可以获得相对简单的 nawfal 建议,而没有只能连接无逗号字符串的缺点正确。
SELECT events._id, events.name,
(group_concat(replace(distinct speakers.name),'',''), ' - ') AS speaker_names,
(group_concat(replace(distinct speakers.name),'',''), ' - ') AS term_names
FROM events
LEFT JOIN
(SELECT et.event_id, ts.name
FROM terms ts
JOIN events_terms et ON ts._id = et.term_id
) terms ON events._id = terms.event_id
LEFT JOIN
(SELECT sp._id, es.event_id, sp.name
FROM speakers sp
JOIN events_speakers es ON sp._id = es.speaker_id
) speakers ON events._id = speakers.event_id
GROUP BY events._id;
但实际上我会认为这是 SQLite 错误/不一致,还是我遗漏了什么?
【讨论】:
感谢您抽出宝贵时间撰写本文!自从解决这个问题以来,我已经有很长时间了,但经过几分钟的审查,我不得不同意这似乎是一个不一致的地方;我希望 group_concat 支持具有不同的自定义分隔符。我认为这两种解决方案都很难理解(一旦揭示!),并且更喜欢不需要调用什么都不做的函数的解决方案。 这不起作用。正如 Mi-La 在他们的回答中所做的编辑也承认。 distinct 关键字不再具有预期效果。 distinct 关键字确实对我有预期的效果(ios 应用程序中的 sqlite)所以这个解决方案对我来说效果很好,谢谢!【参考方案5】:相互独立地查找说话者/术语名称:
SELECT _id,
name,
(SELECT GROUP_CONCAT(name, ';')
FROM events_speakers
JOIN speakers
ON events_speakers.speaker_id = speakers._id
WHERE events_speakers.event_id = events._id
) AS speaker_names,
(SELECT GROUP_CONCAT(name, ';')
FROM events_terms
JOIN terms
ON events_terms.term_id = terms._id
WHERE events_terms.event_id = events._id
) AS term_names
FROM events
【讨论】:
太好了,非常感谢。我获得了更多了解 SQL 的额外好处。【参考方案6】:奇怪的是 SQLite 不支持!
有被否决的风险,只有在有帮助的情况下:
您可以使用Replace(X, Y, Z)
。但是你必须确保你的列中没有有效的,
值..
SELECT events._id, events.name,
REPLACE(group_concat(distinct speakers.name), ',', ' - ') AS speaker_names,
REPLACE(group_concat(distinct terms.name), ',', ' - ') AS term_names
FROM events
LEFT JOIN
(SELECT et.event_id, ts.name
FROM terms ts
JOIN events_terms et ON ts._id = et.term_id
) terms ON events._id = terms.event_id
LEFT JOIN
(SELECT sp._id, es.event_id, sp.name
FROM speakers sp
JOIN events_speakers es ON sp._id = es.speaker_id
) speakers ON events._id = speakers.event_id
GROUP BY events._id;
【讨论】:
这是我自己使用的解决方案,所以我不会投反对票。避免替换合法逗号可能失败的答案当然是公认的答案:)谢谢您的时间。 replace(x,y,z) 为我做了。塔。 我也这样做了,但确实有重复...叹息以上是关于sqlite3 JOIN,GROUP_CONCAT 使用不同的自定义分隔符的主要内容,如果未能解决你的问题,请参考以下文章