Как вы кодируете SQL-запрос, который определяет, является ли таблица A правильным подмножеством таблицы B?

#sql #postgresql #set-theory

#sql #postgresql #теория множеств

Вопрос:

Если A является правильным подмножеством B или наоборот, то запрос должен возвращать true . если нет, то false:

Если A или B являются правильным набором друг друга, тогда true . если A или B являются неправильным набором друг друга, тогда 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.

Вывод 'True'

Кто-нибудь знает, что не так с моим кодом?

Комментарии:

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)