检查查询是不是包含 oracle 中子查询的所有值
Posted
技术标签:
【中文标题】检查查询是不是包含 oracle 中子查询的所有值【英文标题】:Check that a query contains all the values of a subquery in oracle检查查询是否包含 oracle 中子查询的所有值 【发布时间】:2020-03-04 19:05:28 【问题描述】:假设您有一个查询,并且您只想显示具有子查询所有值的那个。例如,我们有下表:
CREATE TABLE test
(
code VARCHAR2(4),
year VARCHAR2(4),
action VARCHAR2(50),
CONSTRAINT pk PRIMARY KEY (code, year)
);
还有以下寄存器:
INSERT INTO test
VALUES ('1','2020','Departure');
INSERT INTO test
VALUES ('1','2021','Arrival');
INSERT INTO test
VALUES ('2','2020','Departure');
想象一个子查询返回以下值:
('Departure','Arrival')
所以我想做一个查询,它只返回与子查询中返回的两个值相匹配的代码和年份。查看寄存器,它应该只返回 return ('1','2020') 和 ('1','2021') 因为它们是唯一的动作是 'Arrival' 和 'Departure' 的。我该怎么办?
【问题讨论】:
您是否在任何地方尝试过您的代码?如果代码是一个PK,为什么你有2行代码='1'?数据应该在 2 行,还是只有一个就足够了? (例如在您的数据中,如果我们省略了PK问题,它应该返回1、2020、2021 一行,还是1,2020 和1,2021 2 行? 抱歉,刚刚更正了 【参考方案1】:将您的查询包含在这样的 CTE 中:
with cte as (
<your query here>
)
select t.*
from test t
where
t.action in (select action from cte)
and
code in (
select code
from test
where action in (select action from cte)
group by code
having count(distinct action) = (select count(*) from cte)
)
IN 的子查询返回包含查询返回的所有操作的所有代码。 请参阅demo。 结果:
> CODE | YEAR | ACTION
> :--- | :--- | :--------
> 1 | 2021 | Arrival
> 1 | 2020 | Departure
【讨论】:
但它只检查巧合的数量,对吧? 在我的回答中查看演示。 不,它不只检查巧合的数量。它使用where action in select action from cte
过滤表,然后计算不同的巧合数。如果它们相等,则表示该代码包含 cte 的所有值。【参考方案2】:
作为一般解决方案,我会寻找使用HAVING count(*) = #
的机会。大概,
SELECT code FROM table WHERE action in (SUBSELECT) GROUP BY code HAVING count(*) = (SELECT count(*) from SUBSELECT)
当然,如果单个code
可以有多个Arrival
,则还必须包含DISTINCT
。大概,
SELECT code FROM (SELECT code, distinct(action) FROM table) WHERE action in...
我担心这样的查询的性能,但您必须在现场检查它,因为大多数数据库引擎都能够转换这样的复杂查询以提高效率。
===
如果您确定每个代码的每种类型只有一个操作,我认为 JOIN 也可以工作。例如。
SELECT t.code FROM SUBQUERY as s RIGHT JOIN table as t on t.action = s.action GROUP by t.code HAVING count(*) = (SELECT COUNT(*) FROM SUBQUERY)
(在任何一种情况下都可以,如果要内联子查询以避免重复执行它,您应该使用 @forpas 建议的 CTE 功能)。
【讨论】:
是的,但这只是 2 个值的示例。想象一下同样的情况,但不是“Arrival”和“Departure”,而是在子查询中有 400 个值。 对不起。将其修复为使用=
而不是 >
。从逻辑上讲,该提案仍然有效。您想要任何包含过滤器中所有 400 行的对象。
我的意思是,这句话只会检查匹配的数量是否相同,但不会检查它们是否真的相同。例如,如果子查询返回 2 个值('Hello' 和 'Bye')并且寄存器也有 2 个值('Hello' 和 'Hello2'),它将显示该代码,因为它们都有 2 个值。
没有。 WHERE action in (SUBSELECT)
部分确保我们只考虑在您的列表中有操作的行。
是的,但如果只有其中一个在子选择中,它将返回 true。我们正在寻找的是检查所有操作是否都在子查询中。【参考方案3】:
稍加扩展的样本数据,其中CODE
s 1 和 3 都有 Arrival 和 Departure:
SQL> with test (code, year, action) as
2 (select 1, 2020, 'Departure' from dual union all
3 select 1, 2021, 'Arrival' from dual union all
4 select 2, 2020, 'Departure' from dual union all
5 --
6 select 3, 2018, 'Arrival' from dual union all
7 select 3, 2019, 'Departure' from dual
8 ),
9 subq as
10 (select distinct action,
11 count(distinct action) over () cnt_da
12 from test
13 )
14 select a.code, a.year
15 from test a join subq s on a.action = s.action
16 where s.cnt_da = (select count(distinct action)
17 from test b
18 where b.code = a.code
19 );
CODE YEAR
---------- ----------
1 2021
1 2020
3 2019
3 2018
SQL>
另一个选项,使用MINUS
集合运算符:
SQL> with test (code, year, action) as
2 (select 1, 2020, 'Departure' from dual union all
3 select 1, 2021, 'Arrival' from dual union all
4 select 2, 2020, 'Departure' from dual union all
5 --
6 select 3, 2018, 'Arrival' from dual union all
7 select 3, 2019, 'Departure' from dual
8 ),
9 subq as
10 (select distinct action from test) --> this is your "subquery"
11 select code, year
12 from test a
13 where (select s.action from subq s
14 minus
15 select b.action from test b where b.code = a.code
16 ) is null;
CODE YEAR
---------- ----------
1 2020
1 2021
3 2018
3 2019
SQL>
【讨论】:
但该查询正在计算和比较结果。我希望它从字面上比较它们。 我添加了另一个选项;请看一下。 哦。这是不礼貌的。谢谢@forpas,以后我会尽量避免出现“到达和出发”问题。 那么你应该避免这种情况:***.com/questions/60681353/… 已经看过并成功跳过了这次,@forpas。谢谢:)以上是关于检查查询是不是包含 oracle 中子查询的所有值的主要内容,如果未能解决你的问题,请参考以下文章