Почему эти два sql оператора не возвращают одинаковый результат? - PullRequest
0 голосов
/ 26 апреля 2020

Я только начинаю с sql и хочу преобразовать это:

select X.persnr 
from Pruefung X 
where X.persnr in (
    select Y.persnr 
    from pruefung Y 
    where X.matrikelnr <> Y.matrikelnr)

вывод:

enter image description here

в тот же вывод, но с использованием формы соединения. Я попробовал это так, как показано ниже, но я не могу «избавиться» от декартового произведения, насколько я вижу. Или, может быть, я неправильно понял приведенное выше утверждение, что оно должно делать на самом деле Для меня выше сказанное говорит "для каждого уникального отображения матрицы все соответствующие персны".

select X.persnr 
from Pruefung X 
join pruefung y on x.persnr=y.persnr 
where x.matrikelnr<>y.matrikelnr

вывод: длинный список (я не хочу заполнять им весь вопрос) - я предполагаю декартово произведение из объединения

Это отношение, которым я являюсь using.

Relation I am using

Edit: Distinct (если я использую его не в том месте) не будет работать, потому что тогда persnr отображается только один раз, вот и все но не цель.

Ответы [ 3 ]

1 голос
/ 26 апреля 2020

Вы можете написать свой первый запрос с помощью EXISTS вместо IN, например:

select X.persnr 
from Pruefung X 
where exists (
    select 1 
    from pruefung Y 
    where X.persnr = Y.persnr and X.matrikelnr <> Y.matrikelnr
)

Таким образом, очевидно, что этот запрос означает:

вернуть все persnr s таблицы, для которой существует другая строка с таким же persnr, но другим matrikelnr

Для ваших данных выборки результатом являются все persnr s таблицы.

Ваш второй запрос делает что-то другое. Он связывает каждую строку таблицы со всеми строками одной и той же таблицы с одинаковыми persnr, но разными matrikelnr. Таким образом, для каждой строки таблицы вы получите столько строк, сколько имеется для тех же persnr с, но разных matrikelnr с. Например, для 1-й строки с persnr = 101 и matrikelnr = 8532478 вы получите 2 строки, потому что в таблице есть 2 строки с persnr = 101 и matrikelnr <> 8532478.

1 голос
/ 26 апреля 2020

Ваш первоначальный запрос действительно: выберите persnr из Pruefung, если тот же самый persnr существует для другого matrikelnr.

"для каждого уникального matrikelnr отобразить все соответствующие persnr" Это достигается с помощью агрегации:

В зависимости от используемой СУБД вы можете использовать что-то вроде (SQL Сервер использует STRING_AGG, но MySQL использует GROUP_CONCAT)

SELECT matrikelnr,STRING_AGG(matrikelnr,',')
GROUP BY matrikelnr

Вы не можете легко достичь того, что вы получили от коррелированного запроса (ваш Первая попытка) с использованием объединения.

Редактировать: Объединение не приводит к ожидаемому «декартову произведению», когда нет условия объединения (CROSS JOIN). Объединение соответствует двум наборам на основе условия объединения. Причина, по которой вы получаете больше записей, состоит в том, что соединение просматривает ключ соединения (PERSNR) и выполняет его сопоставление.

Например, для 101 у вас есть 3 записи. Это означает, что вы получите 3х3 результата. Затем вы фильтруете результаты для случаев, когда X.matrikelnr <> Y.matrikelnr Если мы предположим, что matrikelnr уникален, это будет означать, что строка соответствует самому себе. таким образом, вы потеряете 3 результата, в результате чего получите 3x3 - 3 = 6.

Если вы хотите достичь чего-то в SQL, вы должны сначала определить, что вы ожидаете использовать, а затем использовать соответствующие инструменты (в этом коррелированные по регистру запросы не включаются)

0 голосов
/ 26 апреля 2020

Вы правы. Это вина декартового произведения. Предположим, у вас есть persnr 1,1,1,2,2,2 в первой таблице и persnr 1,1,1,2,2 во второй таблице. Сколько строк вы ожидаете вернуть? В коде pdeuso это будет go вот так

Select 
...
WHERE persnr in (second table) 
-- 6 lines

Select persnr
FROM ...
JOIN ... ON a.persnr = b.persnr
-- 3X3 + 3X2 = 15 lines.

SELECT DISTINCT persnr
FROM ...
JOIN ... ON a.persnr = b.persnr
-- 2 lines (1 and 2)

Выберите

...