Объединения дают вам дубликаты, потому что они включают в себя более одной таблицы, представляющей отношение «многие ко многим», а фильтрации недостаточно, чтобы помешать таблицам «многие ко многим» возвращать более одной строки в зависимости от заданных условий объединения..
Вы можете избежать дубликатов, введя полусоединение в форме предиката EXISTS и затем переместив туда некоторые таблицы.Вот один из возможных способов использования EXISTS в вашей ситуации:
SELECT
stores.state,
SUM(qty * price)
FROM sales
INNER JOIN stores ON sales.stor_id = stores.stor_id
INNER JOIN titles ON sales.title_id = stores.title_id
WHERE EXISTS (
SELECT *
FROM authors a
INNER JOIN titelauthor ta ON a.au_id = ta.au_id
WHERE ta.titel_id = titles.title_id
AND a.state LIKE stores.state
)
GROUP BY
stores.state
Центральный стол, скорее всего, sales
, отсюда и цифры.Поэтому запрос строится вокруг sales
.Другие таблицы объединяются явно (с помощью предложения JOIN), если они возвращают только одну строку для каждой строки sales
.Как только таблица вернет более одной строки, она перемещается в EXISTS.
Есть еще одна вещь.Работая над этим запросом, я заметил, что одно соединение может быть избыточным (как в вашем запросе, так и в моем).Таблица составляет titles
.Если ваши внешние ключи в порядке, вам не нужно присоединяться к titles
, так как titleauthor
может быть присоединен непосредственно к stores
на title_id
.(Даже если у вас нет соответствующих внешних ключей, вам все равно не нужно включать titles
, поскольку любые возможные несуществующие заголовки, на которые ссылаются либо titleauthor
, либо sales
, будут отфильтрованы в любом случае.)
Таким образом, окончательный запрос может выглядеть следующим образом:
SELECT
stores.state,
SUM(qty * price)
FROM sales
INNER JOIN stores ON sales.stor_id = stores.stor_id
WHERE EXISTS (
SELECT *
FROM authors a
INNER JOIN titelauthor ta ON a.au_id = ta.au_id
WHERE ta.titel_id = sales.title_id
AND a.state LIKE stores.state
)
GROUP BY
stores.state