Убедитесь, что запрос содержит все значения подзапроса в oracle - PullRequest
0 голосов
/ 04 марта 2020

Представьте, что у вас есть запрос, и вы хотите показать только того, у кого ВСЕ значения подзапроса. Например, у нас есть следующая таблица:

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'), потому что они единственные, чьи действия - «Прибытие» и «Отъезд». Как я мог это сделать?

Ответы [ 3 ]

0 голосов
/ 04 марта 2020

Заключите ваш запрос в 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 возвращает все коды, которые содержат все действия, которые возвращает ваш запрос. Смотрите демо . Результаты:

> CODE | YEAR | ACTION   
> :--- | :--- | :--------
> 1    | 2021 | Arrival  
> 1    | 2020 | Departure
0 голосов
/ 04 марта 2020

С немного расширенными образцами данных, где CODE s 1 и 3 имеют и Прибытие, и Отправление:

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>
0 голосов
/ 04 марта 2020

В качестве общего решения я бы искал возможность использовать HAVING count(*) = #. Грубо говоря,

ВЫБРАТЬ код из таблицы ГДЕ действие в (ПОСЛЕДУЮЩИЙ) ГРУППА ПО КОДУ СЧИТАЕТСЯ (*) = (ВЫБРАТЬ счетчик (*) из ПОДСОБРАЖЕННЫХ)

Конечно если вы можете иметь несколько Arrival для одного code, вы должны также включить DISTINCT. Грубо говоря,

ВЫБЕРИТЕ код ОТ (ВЫБЕРИТЕ код, отличный (таблица) от действия) ОТ ГДЕ действие в ...

Я беспокоюсь о производительности запроса, подобного этому , но вам придется проверить это на месте, поскольку большинство механизмов баз данных имеют возможность преобразовывать сложные запросы, подобные этим, для повышения эффективности.

===

Я думаю, что JOIN также будет работать, если Вы уверены, что для каждого кода существует только одно действие каждого типа. Например.

ВЫБЕРИТЕ t.code ИЗ SUBQUERY в качестве таблицы s RIGHT JOIN как t в t.action = s.action GROUP по t.code HAVING count (*) = (SELECT COUNT (*) FROM SUBQUERY)

(и да, в любом случае вы должны использовать функции CTE, такие как @forpas, если вы собираетесь встроить подзапрос, чтобы избежать его повторного выполнения).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...