#mysql #group-by #left-join
#mysql #группировка по #левое соединение
Вопрос:
Мои таблицы:
t1
col_a col_b
1 100
1 200
1 300
2 400
t2
col_a col_b
100 5
100 6
t3
col_a col_b
5 100
6 200
6 300
Если я выполняю запрос и оставляю 3 таблицы в порядке, я получаю:
1 100 5 100
1 100 6 200
1 100 6 300
1 200 null null
1 300 null null
2 400 null null
Если я добавлю группу по t1.col_a, t2.col_b:
1 100 5 100
1 100 6 (200 or 300)
1 (200 or 300) null null
2 400 null null
Но я не хочу, чтобы отображалась 3-я строка, потому что она не имеет значения в t2.col_b. Я мог бы добавить условие, при котором этот столбец не равен null, но это удалило бы последнюю строку, которая должна остаться.
В идеальном запросе я хотел бы видеть:
1 100 5 100
1 100 6 (200 or 300)
2 400 null null
Комментарии:
1. Почему вам нужна не 3-я строка, а последняя строка. Обе строки не имеют отношения к t2. Невозможно удалить одну строку и получить другую, если у вас нет правила.
2. в основном первая таблица представляет пользователя, вторая — свойство пользователя, третья — свойство свойства. я хочу, чтобы все пользователи показывали, есть ли у них какие-либо назначенные свойства — вот почему последняя строка должна остаться. я не хочу, чтобы эта третья строка отображалась, потому что у меня уже есть две строки для этого пользователя. я понимаю, что во втором столбце результатов есть уникальная информация, но я действительно забочусь только о дублировании пользовательских строк, когда третья таблица уникальна.
Ответ №1:
Попробуйте это. t1.col_b немного сложнее, потому что, если существует несколько значений t1.col_a без ссылки на t2, этот запрос выбирает случайное значение для этого.
SELECT
sub.col_a,
IFNULL(sub.relation,t1.col_b),
t2.col_b,
t3.col_b
FROM(
SELECT
t1.col_a,
group_concat(DISTINCT t2.col_a) AS relation
FROM table1 AS t1
LEFT JOIN table2 AS t2 ON t2.col_a = t1.col_b
GROUP BY t1.col_a
) AS sub
LEFT JOIN table1 AS t1
ON t1.col_a = sub.col_a
AND (t1.col_b IN (sub.relation) OR sub.relation IS NULL)
LEFT JOIN table2 AS t2
ON t2.col_a = t1.col_b
LEFT JOIN table3 AS t3
ON t3.col_a = t2.col_b
GROUP BY t1.col_a, t2.col_b
Ответ №2:
Один из подходов заключается в выборе только ненулевых строк как части результата, а затем объединении его с более широким, но сгруппированным набором результатов:
SELECT * FROM t1
JOIN t2 ON t1.col_b = t2.col_a
LEFT JOIN t3 ON t2.col_b = t3.col_a
UNION
SELECT * FROM t1
LEFT JOIN t2 ON t1.col_b = t2.col_a
LEFT JOIN t3 ON t2.col_b = t3.col_a
GROUP BY t1.col_a
Обратите внимание, что в первом запросе нет ЛЕВОГО СОЕДИНЕНИЯ. Это потому, что мы не хотим никаких нулевых результатов в этом запросе. Этот запрос дает вам:
t1.col_a t2.col_a t3.col_a t3.col_b
1 100 5 100
1 100 6 200
1 100 6 300
И второй запрос дает вам:
t1.col_a t2.col_a t3.col_a t3.col_b
1 100 5 100
2 400 NULL NULL
Наконец, когда вы выполняете ОБЪЕДИНЕНИЕ, оно избавляется от повторяющегося результата (первая строка в первом результирующем наборе равна первой строке во втором результирующем наборе). Это поведение команды ОБЪЕДИНЕНИЯ по умолчанию, приводящее к:
t1.col_a t2.col_a t3.col_a t3.col_b
1 100 5 100
1 100 6 200
1 100 6 300
2 400 NULL NULL