关于mysql:UNION ALL返回多个结果

UNION ALL is returning multiple results

本问题已经有最佳答案,请猛点这里访问。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
        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

enter image description here


不了解任何关于模式或数据形状的信息,您可以通过简化查询来获得所需的内容。假设大致符合标准的SQL方言

  • 您不需要随附的select。全选(unioned select表达式)接受order by,该order by应用于整个全选。

  • UNION中的单个select语句中不需要distinct关键字:UNION本身消除了重复行。

请在编写一个长而复杂的查询时,花些时间对其进行格式化,以便下一个必须理解它的SOD(几年后可能是您)能够轻松地完成这项工作。

这就相当于:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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的连接标准有一系列测试:

1
2
3
4
5
6
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子句和相关表的联接标准,从而:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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%正确,但您应该能够了解其中的要点):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

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


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

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