@jazzman7

Как получать значения только из одной таблицы при join?

Добрый день!

Есть две таблицы

servers_texts
id cat_id id
8 10 1
9 5 2
10 4 3
11 3 4

и servers_world
cat_id typew
10 1
10 2
10 1
11 2

servers_texts - категории, servers_world - элементы категорий, где `servers_world`.`cat_id` айди родительского servers_texts.
Задача: выводить, те элементы servers_texts у потомков которых в servers_world определенный тип typew.

Наглядно: есть категория "10", ей принадлежат несколько потомков servers_world с типом 1, но вместо того чтобы вывести категорию один раз, мой запрос выводит два раза потому-что в servers_world 2 совпадения. Подскажите, пожалуйста, как пофиксить?

SELECT `servers_texts`.*, `servers_world`.`typew` FROM `servers_texts` LEFT JOIN `servers_world` ON `servers_texts`.`id` = `servers_world`.`cat_id` WHERE `servers_texts`.`premod` = 1 AND `servers_texts`.`cat_id` = ' 10' AND `servers_world`.`typew` = ' 1' ORDER BY `vote` DESC, `servers_texts`.`id` DESC
  • Вопрос задан
  • 117 просмотров
Решения вопроса 1
@Miron11
Пишу sql 20 лет. Срок :)
У Вас 2 варианта,
1. использовать отфильтрованный список servers_world
2 использовать значение typew в контексте выборки ( так же с фильтром )
1-й подход может, в свою очередь, иметь два подхода, в зависимости от того, какие фишки SQL поддерживает Ваша СУБД.

1. C(ommon) T(able) E(xpression):

WITH filtered_servers_world AS (
SELECT DISTINCT cat_id, typew
FROM filtered_servers_world
)
SELECT `servers_texts`.*
, `filtered_servers_world`.`typew`
FROM `servers_texts`
LEFT JOIN `filtered_servers_world` ON `servers_texts`.`id` = `filtered_servers_world`.`cat_id`
WHERE `servers_texts`.`premod` = 1
AND `servers_texts`.`cat_id` = ' 10'
AND `filtered_servers_world`.`typew` = ' 1'
ORDER BY `vote` DESC, `servers_texts`.`id` DESC

2. Sub-Query с алиасом:
SELECT `servers_texts`.*
, `filtered_servers_world`.`typew`
FROM `servers_texts`
LEFT JOIN (SELECT DISTINCT cat_id
, typew
FROM `servers_world`) AS `filtered_servers_world`
ON `servers_texts`.`id` = `filtered_servers_world`.`cat_id`
WHERE `servers_texts`.`premod` = 1
AND `servers_texts`.`cat_id` = ' 10'
AND `filtered_servers_world`.`typew` = ' 1'
ORDER BY `vote` DESC, `servers_texts`.`id` DESC

3. inline используя контекст выборки данных, менее эффективно, но иногда работает лучше подходов 1, 2 в частности, когда СУБД распределенная, поскольку уменьшает количество раз данные копируются между порциями данных разделенных на разные машины

SELECT *
FROM (
SELECT `servers_texts`.*
, (SELECT MAX(`servers_world`.`typew`) FROM `servers_world` WHERE `servers_world`.`cat_id` = `servers_texts` .`cat_id`) AS `typew`
FROM `servers_texts`
WHERE `servers_texts`.`premod` = 1
AND `servers_texts`.`cat_id` = ' 10'
) AS `dt`
WHERE `typew` = '1'
AND `premod` = 1
AND `cat_id` = ' 10'
ORDER BY `vote` DESC, `servers_texts`.`id` DESC

4 lateral join или outer apply

SELECT `servers_texts`.*
, `filtered_servers_world`.`typew`
FROM `servers_texts`
LEFT JOIN LATERAL (
SELECT `typew`
FROM `servers_world`
WHERE `servers_world`.`cat_id` = `servers_texts`.`cat_id`
ORDER BY `typew` DESC
LIMIT 1
) `filtered_servers_world` ON TRUE
WHERE `servers_texts`.`premod` = 1
AND `servers_texts`.`cat_id` = ' 10'
AND `filtered_servers_world`.`typew` = ' 1'
ORDER BY `vote` DESC, `servers_texts`.`id` DESC

Заметьте, я поменял поле на котором servers_texts и servers_world установили родство. В Вашем оригинальном запросе поле servers_texts использует id в JOIN выражении, но глядя на поля предложенные в таблицах cat_id выглядит, как поле, которое больше подходит.
Возможно я не прав, пожалуйста проверьте.
В крайнем случае, пожалуйста верните оригинальное поле.

-- Удачи
Ответ написан
Ваш ответ на вопрос

Вопрос закрыт для ответов и комментариев

Потому что уже есть похожий вопрос.
Похожие вопросы