如何在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.createdDATETIMETIMESTAMP,您需要这个而不是 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 不会执行您想要的操作。