MySQL — Сгруппируйте 2 строки на основе разных столбцов

#mysql #sql

#mysql #sql

Вопрос:

Я пытаюсь группировать строки на основе других столбцов.

Вот как выглядит таблица:

 | a_id | a_name | b_id | b_name | c_id | c_name | d_id | d_name |
|------|--------|------|--------|------|--------|------|--------|
|   1  | abcdef |   0  |        |   0  |        |   0  |        |
|   2  |   zxy  |   0  |        |   0  |        |   0  |        |
|   3  |  lmao  |   0  |        |   0  |        |   0  |        |
|   0  |        |   1  |   oop  |   0  |        |   0  |        |
|   0  |        |   2  | abcdef |   0  |        |   0  |        |
|   0  |        |   0  |        |   1  |  nope  |   0  |        |
|   0  |        |   0  |        |   2  | nothing|   0  |        |
|   0  |        |   0  |        |   0  |        |   1  | abcdef |
|   0  |        |   0  |        |   0  |        |   2  |  oop   |
|   0  |        |   0  |        |   0  |        |   3  | turtles|
  

Я хочу, чтобы все похожие имена были объединены в одну строку. Сходство определяется определяемой пользователем функцией IS_SAME(str1, str2).

Вот как должен выглядеть результат.

 | a_id | a_name | b_id | b_name | c_id | c_name | d_id | d_name |
|------|--------|------|--------|------|--------|------|--------|
|   1  | abcdef |   2  | abcdef |   0  |        |   1  | abcdef |
|   2  |   zxy  |   0  |        |   0  |        |   0  |        |
|   3  |  lmao  |   0  |        |   0  |        |   0  |        |
|   0  |        |   1  |   oop  |   0  |        |   2  |  oop   |
|   0  |        |   0  |        |   1  |  nope  |   0  |        |
|   0  |        |   0  |        |   2  | nothing|   0  |        |
|   0  |        |   0  |        |   0  |        |   3  | turtles|
  

На самом деле я создал запрос для этого, но я использовал всю последнюю теорему Ферма и не сохранил используемый мной запрос (я сохранил предыдущие 5 запросов, которые я использовал для ведения этого списка), потому что я чувствовал, что это слишком просто для записи.

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

1. Разрешено ли нам предлагать нормализацию?

Ответ №1:

Это сложно, но выполнимо. Вы хотите начать со списка имен, а затем объединить в каждой таблице и объединить в первом столбце:

 select max(ta.a_id) as a_id, max(ta.a_name) as a_name,
       max(tb.b_id) as a_id, max(tb.b_name) as b_name,
       max(tc.c_id) as a_id, max(tc.c_name) as c_name,
       max(td.d_id) as a_id, max(td.d_name) as d_name       
from (select a_name as name from table t union select b_name union select c_name union select d_name
     ) names left outer join
     table ta
     on is_same(ta.a_name, names.name) left outer join
     table tb
     on is_same(tb.b_name, names.name) left outer join
     table tc
     on is_same(tc.c_name, names.name) left outer join
     table td
     on is_same(td.d_name, names.name)
group by names.name;
  

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

1. Как я могу использовать свою функцию IS_SAME() для сравнения вместо того, чтобы создавать группу, которая предполагает 100% сходство?

2. @Nikzilla . , , Это то, что делает этот запрос.

3. Ох. Что ж, в таком случае я проверю это! Не кодируйте, когда устали!

4. если group by names.name могут быть повторяющиеся строки из-за разных имен с is_same(..) = true . возможно, потребуется дедуплицировать результат.

5. @Fabricator . , , В вашем вопросе, похоже, нет примеров таких дубликатов. В любом случае, group by дубликаты удаляются и выбирается одно из значений. Вы можете использовать group_concat() для получения всех значений в столбце.