#sql #postgresql #set-theory
#sql #postgresql #теория множеств
Вопрос:
Если A является правильным подмножеством B или наоборот, то запрос должен возвращать true . если нет, то false:
Это код для создания таблицы A и таблицы B:
Create table A (i int);
Create table B (i int);
Insert into A values (1);
Insert into A values (2);
Insert into A values (3);
Insert into B values (2);
Insert into B values (3);
Insert into B values (6);
Это код, который я написал:
SELECT Count(*) >= 1
FROM A
RIGHT JOIN B ON A=B
WHERE A IS NULL;
Я получаю значение true, но оно должно быть false.
Кто-нибудь знает, что не так с моим кодом?
Комментарии:
1. Пожалуйста, объясните, что «A и B являются правильным набором друг друга» на словах. Никто не владеет теорией множеств.
2. Вы ищете
intersect
оператор? dbfiddle.uk /…3. @LaurenzAlbe: Я думаю, что OP хочет false , но они получают true (здесь ни один набор данных не содержится в другом).
4. Но было бы хорошо, если бы @user14217364 мог подтвердить!
5. @GMB Ах, OP говорит о правильных подмножествах , а не о правильных наборах. И я боялся, что забыл свою теорию множеств… Я пойду исправлю вопрос.
Ответ №1:
Я понимаю, что вы хотите, чтобы запрос проверял, является ли либо A правильным подмножеством A, либо B является правильным подмножеством A (оба не могут быть истинными одновременно).
A ⊂ B
читается как: каждый элемент A
может быть найден в B
, и не все элементы B
существуют в A
.
В SQL это было бы full join
и условной логикой:
select
(bool_and(b.i is not null) and bool_or(a.i is null)) -- A ⊂ B
or (bool_and(a.i is not null) and bool_or(b.i is null)) -- B ⊂ A
from a
full join b using (i)
Комментарии:
1. Разве это не
intersect
?2. @a_horse_with_no_name: я бы подумал об этом как о двух
except
s, где один должен возвращать что-то, а не другое.
Ответ №2:
Этот ответ не относится к Postgres конкретно.
select 1
from A full outer join B on B.i = A.i
having count(case when A.i is null then 1 end) = 0 or
count(case when B.i is null then 1 end) = 0
Вы сказали «друг о друге», поэтому я разрешил оба варианта. Конечно, вы действительно хотите спросить, является ли A правильным подмножеством B, тогда вы действительно просто хотите:
count(case when A.i is null then 1 end) = 0 and
count(case when B.i is null then 1 end) > 0
Подсчет нулей (на стороне A) также может быть выражен как:
count(*) - count(A.i)
Комментарии:
1. Спасибо, я в курсе обоих этих моментов. Вопрос был плохо сформулирован, когда я на него отвечал.
Ответ №3:
Используя служебные функции intarray
, эта проблема становится намного проще:
WITH A(i) AS (
SELECT *
FROM (VALUES (1),
(2),
(3)) as a
), B(i) AS (
SELECT *
FROM (VALUES (2),
(3),
(6)) as b
)
-- The above is just fake data for A and B
SELECT (SELECT ARRAY_AGG(i) FROM A) <@ (SELECT ARRAY_AGG(i) FROM B)
где <@
находится оператор CONTAINED. Он возвращает, содержится ли левый массив в правом массиве. Если вы хотите учесть любой вариант, вы могли бы просто связать случаи с помощью OR
:
WITH A(i) AS (
SELECT *
FROM (VALUES (1),
(2),
(3)) as a
), B(i) AS (
SELECT *
FROM (VALUES (2),
(3),
(6)) as b
)
-- The above is just fake data for A and B
SELECT (SELECT ARRAY_AGG(i) FROM A) <@ (SELECT ARRAY_AGG(i) FROM B)
OR (SELECT ARRAY_AGG(i) FROM A) @> (SELECT ARRAY_AGG(i) FROM B)