如何在mysql中简化多个UNION ALL?
How to simplify multiple UNION ALL in mysql?
由于多个 UNION ALL,我的查询变得非常庞大,任何人都可以帮助我减少它。 UNION ALL居然有300多个
SELECT keywords,
COUNT(i.postId) as Posts,
SUM(i.interactions) as Interactions,
GROUP_CONCAT(DISTINCT i.users) as Users
FROM (
SELECT 'keyword1' as keywords,
`postId`,
`interactions`,
( SELECT displayName FROM profile WHERE id=userID LIMIT 1 ) as users
FROM `posts`
WHERE `content` REGEXP 'keyword1'
AND created BETWEEN '2021-01-01' AND '2021-02-19'
AND userID IN (147483,166451,166467)
UNION ALL
SELECT 'keyword2' as keywords,
`postId`,
`interactions`,
( SELECT displayName FROM profile WHERE id=userID LIMIT 1 ) as users
FROM `posts`
WHERE `content` REGEXP 'keyword2'
AND created BETWEEN '2021-01-01' AND '2021-02-19'
AND userID IN (147483,166451,166467)
UNION ALL
SELECT 'keyword3' as keywords,
`postId`,
`interactions`,
( SELECT displayName FROM profile WHERE id=userID LIMIT 1 ) as users
FROM `posts`
WHERE `content` REGEXP 'keyword3'
AND created BETWEEN '2021-01-01' AND '2021-02-19'
AND userID IN (147483,166451,166467)
) i
GROUP BY keywords
在这种情况下,有助于记住 SQL 是一种 声明性语言, 不是 程序性 语言。你描述你想要什么。
您似乎有一个包含 300 个关键字的列表,您希望使用这些关键字来总结您的 content
专栏。
假设您将这些关键字存储在名为 keywords
的 table 中。
并且,假设您的 profile
table 的主键是 id
,匹配 posts.userId
。这意味着我们可以使用 JOIN 而不是一堆子查询来检索用户的 displayName
值。
然后你可以这样写你的查询。我们将从这个子查询开始检索与您的关键字匹配的行的详细信息。
SELECT keywords.keyword,
posts.content, posts.postId,
posts.interactions,
profile.displayName
FROM posts
JOIN profile ON posts.userId = profile.id
JOIN keywords ON post.content RLIKE keywords.keyword
WHERE posts.created BETWEEN '2021-01-01' AND '2021-02-19'
AND posts.userID in (147483,166451,166467)
这会生成一个虚拟 table,其中包含您要汇总的帖子。您应该对此进行测试并说服自己它是正确的。
然后通过更改查询的 SELECT 并添加 GROUP BY 来总结它们,就像这样。
SELECT keywords.keyword,
COUNT(*) count,
SUM(posts.interactions) interactions,
GROUP_CONCAT(DISTINCT profile.displayName ORDER BY profile.displayName) users
FROM posts
JOIN profile ON posts.userId = profile.id
JOIN keywords ON post.content RLIKE keywords.keyword
WHERE posts.created BETWEEN '2021-01-01' AND '2021-02-19'
AND posts.userID in (147483,166451,166467)
GROUP BY keywords.keyword;
大功告成。将关键字列表移动到它们自己的 table 是摆脱巨大的 UNION ALL 级联的秘诀。
您可能会发现此行比使用正则表达式稍微快一些。
JOIN keywords ON post.content LIKE CONCAT('%', keywords.keyword, '%')
最后,如果 posts.created
是 DATETIME
或 TIMESTAMP
,您需要这个而不是 created BETWEEN
,这样您就可以获得范围最后一天的所有项目。请注意范围末尾的 <
。
WHERE posts.created >= '2021-01-01'
AND posts.created < '2021-02-19' + INTERVAL 1 DAY
您需要将此条件用于日期范围的结束,因为日期常量 2021-02-19
实际上表示 2021-02-19 00:00:00
或该日期开始的午夜。例如,2021-02-19 10:22:00
的时间戳是 在午夜 之后,因此 BETWEEN 不会执行您想要的操作。
由于多个 UNION ALL,我的查询变得非常庞大,任何人都可以帮助我减少它。 UNION ALL居然有300多个
SELECT keywords,
COUNT(i.postId) as Posts,
SUM(i.interactions) as Interactions,
GROUP_CONCAT(DISTINCT i.users) as Users
FROM (
SELECT 'keyword1' as keywords,
`postId`,
`interactions`,
( SELECT displayName FROM profile WHERE id=userID LIMIT 1 ) as users
FROM `posts`
WHERE `content` REGEXP 'keyword1'
AND created BETWEEN '2021-01-01' AND '2021-02-19'
AND userID IN (147483,166451,166467)
UNION ALL
SELECT 'keyword2' as keywords,
`postId`,
`interactions`,
( SELECT displayName FROM profile WHERE id=userID LIMIT 1 ) as users
FROM `posts`
WHERE `content` REGEXP 'keyword2'
AND created BETWEEN '2021-01-01' AND '2021-02-19'
AND userID IN (147483,166451,166467)
UNION ALL
SELECT 'keyword3' as keywords,
`postId`,
`interactions`,
( SELECT displayName FROM profile WHERE id=userID LIMIT 1 ) as users
FROM `posts`
WHERE `content` REGEXP 'keyword3'
AND created BETWEEN '2021-01-01' AND '2021-02-19'
AND userID IN (147483,166451,166467)
) i
GROUP BY keywords
在这种情况下,有助于记住 SQL 是一种 声明性语言, 不是 程序性 语言。你描述你想要什么。
您似乎有一个包含 300 个关键字的列表,您希望使用这些关键字来总结您的 content
专栏。
假设您将这些关键字存储在名为 keywords
的 table 中。
并且,假设您的 profile
table 的主键是 id
,匹配 posts.userId
。这意味着我们可以使用 JOIN 而不是一堆子查询来检索用户的 displayName
值。
然后你可以这样写你的查询。我们将从这个子查询开始检索与您的关键字匹配的行的详细信息。
SELECT keywords.keyword,
posts.content, posts.postId,
posts.interactions,
profile.displayName
FROM posts
JOIN profile ON posts.userId = profile.id
JOIN keywords ON post.content RLIKE keywords.keyword
WHERE posts.created BETWEEN '2021-01-01' AND '2021-02-19'
AND posts.userID in (147483,166451,166467)
这会生成一个虚拟 table,其中包含您要汇总的帖子。您应该对此进行测试并说服自己它是正确的。
然后通过更改查询的 SELECT 并添加 GROUP BY 来总结它们,就像这样。
SELECT keywords.keyword,
COUNT(*) count,
SUM(posts.interactions) interactions,
GROUP_CONCAT(DISTINCT profile.displayName ORDER BY profile.displayName) users
FROM posts
JOIN profile ON posts.userId = profile.id
JOIN keywords ON post.content RLIKE keywords.keyword
WHERE posts.created BETWEEN '2021-01-01' AND '2021-02-19'
AND posts.userID in (147483,166451,166467)
GROUP BY keywords.keyword;
大功告成。将关键字列表移动到它们自己的 table 是摆脱巨大的 UNION ALL 级联的秘诀。
您可能会发现此行比使用正则表达式稍微快一些。
JOIN keywords ON post.content LIKE CONCAT('%', keywords.keyword, '%')
最后,如果 posts.created
是 DATETIME
或 TIMESTAMP
,您需要这个而不是 created BETWEEN
,这样您就可以获得范围最后一天的所有项目。请注意范围末尾的 <
。
WHERE posts.created >= '2021-01-01'
AND posts.created < '2021-02-19' + INTERVAL 1 DAY
您需要将此条件用于日期范围的结束,因为日期常量 2021-02-19
实际上表示 2021-02-19 00:00:00
或该日期开始的午夜。例如,2021-02-19 10:22:00
的时间戳是 在午夜 之后,因此 BETWEEN 不会执行您想要的操作。