UNION ALL 正在返回多个结果 [重复]

Posted

技术标签:

【中文标题】UNION ALL 正在返回多个结果 [重复]【英文标题】:UNION ALL is returning multiple results [duplicate] 【发布时间】:2014-06-27 20:51:13 【问题描述】:

此查询返回多个结果。在底部,您可以看到每个 ID 号有两个。如何区分仍然获得 25 条唯一值记录的记录?

        SELECT *
            FROM(
                SELECT
                    DISTINCT cards.id, cards.name, cards.created_at, cards.updated_at
                    FROM cards
                        INNER JOIN card_process
                            ON card_process.card_id = cards.id
                            INNER JOIN processes
                                ON processes.id = card_process.process_id
                                INNER JOIN category_process
                                    ON category_process.process_id = processes.id
                                    INNER JOIN categories
                                        ON categories.id = category_process.category_id
                                        INNER JOIN series
                                            ON series.id = categories.serie_id
                                            INNER JOIN serie_user
                                                ON serie_user.serie_id = series.id
                        AND `cards`.`type` NOT IN ('', 'libraries')
                        AND NOT `cards`.`deleted`
                        AND NOT `categories`.`deleted`
                        AND NOT `series`.`deleted`
                        AND `cards`.`type` IN ('forms')
                        AND `series`.`id` IN (124,235,126,126,201,236,207,207,207,207,247,234,131,131,221,225,225,222)
            UNION ALL
                SELECT
                    DISTINCT cards.id, cards.name, cards.created_at, cards.updated_at
                    FROM cards
                        WHERE `cards`.`account_user_id`='9'
                            AND NOT `cards`.`deleted`
                            AND `cards`.`type` IN ('forms')
            ) AS qry
                ORDER BY `updated_at` ASC
                LIMIT 0, 25

【问题讨论】:

使用UNION 而不是UNION ALL 【参考方案1】:

是的,UNION ALL 就是这样工作的,它只是为您提供两个查询的所有行。

如果要删除重复项,请使用 UNION ,不带 ALL 部分。

【讨论】:

您也可以使用UNION DISTINCT 明确说明。 UNION ALL to UNION 修复了它只是不能再接受 10 分钟。 @Barmar 我没有看到我的结果集有或没有UNION DISTINCT UNIONUNION DISTINCT 相同,它们都删除重复项。 UNION ALL 留下重复项。【参考方案2】:

对架构或数据形状一无所知,您可以通过简化查询来获得所需的信息。假设一个大致符合标准的 SQL 方言

您不需要封闭的select全选(联合选择表达式)采用order by,并且该顺序适用于整个全选

您不需要在union 中的单个select 语句中使用distinct 关键字:union 本身会消除重复行。

并且,当您编写一个长而复杂的查询时,请花一些时间对其进行格式化,以便下一个必须理解它的人(可能是几年后的您)可以轻松地理解它。

这会让你得到等价物:

SELECT cards.id   ,
       cards.name ,
       cards.created_at ,
       cards.updated_at
FROM       cards
INNER JOIN card_process     ON card_process.card_id = cards.id
INNER JOIN processes        ON processes.id = card_process.process_id
INNER JOIN category_process ON category_process.process_id = processes.id
INNER JOIN categories       ON categories.id =  category_process.category_id
INNER JOIN series           ON series.id = categories.serie_id
INNER JOIN serie_user       ON serie_user.serie_id = series.id
                           AND `cards`.`type` NOT IN ('', 'libraries')
                           AND NOT `cards`.`deleted`
                           AND NOT `categories`.`deleted`
                           AND NOT `series`.`deleted`
                           AND `cards`.`type` IN ('forms')
                           AND `series`.`id` IN (124,235,126,126,201,236,207,207,207,207,247,234,131,131,221,225,225,222)
UNION
SELECT cards.id   ,
       cards.name ,
       cards.created_at ,
       cards.updated_at
FROM cards
WHERE `cards`.`account_user_id`='9'
  AND NOT `cards`.`deleted`
  AND `cards`.`type` IN ('forms')
ORDER BY `updated_at` ASC
LIMIT 0, 25

如果 mysql 不允许限制 全选,那么您可能需要封闭的 select 语句。

另外,您可能会注意到您的联接条件几乎肯定不正确。在第一次选择中,serie_user 表的联接条件有一堆测试:

AND `cards`.`type` NOT IN ('', 'libraries')
AND NOT `cards`.`deleted`
AND NOT `categories`.`deleted`
AND NOT `series`.`deleted`
AND `cards`.`type` IN ('forms')
AND `series`.`id` IN (124,235,126,126,201,236,207,207,207,207,247,234,131,131,221,225,225,222)

它们适用于加入来自serie_user 的候选行。它们不适用于整个结果集。它们应该被重构为 where 子句和相关表的连接条件,因此:

SELECT cards.id   ,
       cards.name ,
       cards.created_at ,
       cards.updated_at
FROM       cards
INNER JOIN card_process     ON card_process.card_id        = cards.id
INNER JOIN processes        ON processes.id                = card_process.process_id
INNER JOIN category_process ON category_process.process_id = processes.id
INNER JOIN categories       ON categories.id               =  category_process.category_id
                           AND NOT `categories`.`deleted`
INNER JOIN series           ON series.id                   = categories.serie_id
                           AND NOT `series`.`deleted`
                           AND     `series`.`id`           IN (124,235,126,126,201,236,207,207,207,207,247,234,131,131,221,225,225,222)
INNER JOIN serie_user       ON serie_user.serie_id         = series.id
WHERE `cards`.`type` NOT IN ('', 'libraries')
  AND NOT `cards`.`deleted`
  AND     `cards`.`type` IN ('forms')
UNION
SELECT cards.id   ,
       cards.name ,
       cards.created_at ,
       cards.updated_at
FROM cards
WHERE     `cards`.`account_user_id` = '9'
  AND NOT `cards`.`deleted`
  AND     `cards`.`type` IN ('forms')
ORDER BY `updated_at` ASC
LIMIT 0, 25

我要注意的最后一件事是,您正在加入大量未在结果集中使用的表。您所做的只是从cards 表中获取行的子集。这向我表明,如果您简单地摆脱 union 和所有无关的连接并简单地提出正确的问题,您可能会过得更好。

这完全消除了重复的可能性。

稍微重构一下就可以解决这个问题(不能保证我 100% 正确,但你应该能够理解它的要点):

select c.id         ,
       c.name       ,
       c.created_at ,
       c.updated_at
from cards c
where   not c.deleted
  and       c.type            = 'forms'
  and (     c.account_user_id = '9'
        OR exists ( select *
                    from card_process     cp
                    join processes        p   on     p.id           = cp.process_id
                    join category_process cpx on     cpx.process_id = p.id
                    join categories       c   on     c.id           = cpx.category_id
                                             and not c.deleted
                    join series           s   on     s.id           = categories.serid_id
                                             and not s.deleted
                                             and     series.id IN ( 124 , 235 , 126 , ... )
                    join serie_user       su  on     su.serid_id     = s.id
                    where cp.card_id = c.card_id
                  )
      )
ORDER BY updated_at
LIMIT 0, 25

一个简单的查询通常隐藏在一个复杂的查询中。

【讨论】:

有趣的格式样式。就个人而言,这让我发疯,但我绝对明白你为什么会恳求它。 @beeks:SQL 语法已经够糟糕了。当查询变得复杂时,您需要能够理解它。 O.P. 嵌套连接布局是一种代码味道,表明程序思维(嵌套循环),而不是在集合、关系代数和谓词演算方面表示感谢。此外,许多认知研究表明,规则的表格布局可以增强理解。人们摸索桌子。 @Nicolas Carey,我同意。 OP的代码一团糟,我自己会避免所有像这样的T-SQL。但是你的格式很有趣,但让我难以接受。不过每个人都有自己的。 哇,太棒了!通常我对所有数据库交互都使用 ORM,你有 SQL 的风格指南吗?上面的查询来自我刚刚拿起的SO上其他人的风格。 来自***Transact-SQL (T-SQL) is Microsoft's and Sybase's proprietary...哦该死的...

以上是关于UNION ALL 正在返回多个结果 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

union all和union的区别 怎么使用

union和union all的区别

Union与Union All的区别

hive里面union all的用法记录

Oracle中 union 和 union all 的区别

zbb20180927 Union与Union All的区别