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
UNION
和 UNION 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 正在返回多个结果 [重复]的主要内容,如果未能解决你的问题,请参考以下文章