检查查询是不是包含 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 个值。 对不起。将其修复为使用 = 而不是 &gt;。从逻辑上讲,该提案仍然有效。您想要任何包含过滤器中所有 400 行的对象。 我的意思是,这句话只会检查匹配的数量是否相同,但不会检查它们是否真的相同。例如,如果子查询返回 2 个值('Hello' 和 'Bye')并且寄存器也有 2 个值('Hello' 和 'Hello2'),它将显示该代码,因为它们都有 2 个值。 没有。 WHERE action in (SUBSELECT) 部分确保我们只考虑在您的列表中有操作的行。 是的,但如果只有其中一个在子选择中,它将返回 true。我们正在寻找的是检查所有操作是否都在子查询中。【参考方案3】:

稍加扩展的样本数据,其中CODEs 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 中子查询的所有值的主要内容,如果未能解决你的问题,请参考以下文章

oracle中子查询的使用方法有哪些?

如何创建检查数组是不是包含值的查询?戈朗戈姆

oracle 怎么检查字段是不是存在某值?

特定 OU 中子 OU 中所有用户的 LDAP 查询

Oracle查询某个字段是不是同时包含几个值?

如何使用 django 查询检查数据库字段的所有值是不是相同