#sql #postgresql
#sql #postgresql
Вопрос:
Каждая строка в моей базе данных представляет собой данные JSON. Мне нужно объединить строки на основе поля ‘Match’, что, как я полагаю, означает самосоединение к таблице. Будет ровно 10 строк с одинаковым полем ‘Match’, так что это означает, что мне придется объединяться 10 раз. Это невероятно неэффективно. Есть ли более эффективный способ выполнить приведенный ниже запрос?
SELECT
P1.data->>'Reference_Name',
P2.data->>'Reference_Name',
P3.data->>'Reference_Name',
P4.data->>'Reference_Name',
P5.data->>'Reference_Name',
P6.data->>'Reference_Name',
P7.data->>'Reference_Name',
P8.data->>'Reference_Name',
P9.data->>'Reference_Name',
P10.data->>'Reference_Name'
from match_player_data P1
INNER JOIN match_player_data P2
on P1.data->>'Match' = P2.data->>'Match'
and P1.data->>'Reference_Name' <> P2.data->>'Reference_Name'
INNER JOIN match_player_data P3
on P1.data->>'Match' = P3.data->>'Match'
and P1.data->>'Reference_Name' <> P3.data->>'Reference_Name'
and P2.data->>'Reference_Name' <> P3.data->>'Reference_Name'
INNER JOIN match_player_data P4
on P1.data->>'Match' = P4.data->>'Match'
and P4.data->>'Reference_Name' <> P1.data->>'Reference_Name'
and P4.data->>'Reference_Name' <> P2.data->>'Reference_Name'
and P4.data->>'Reference_Name' <> P3.data->>'Reference_Name'
INNER JOIN match_player_data P5
on P1.data->>'Match' = P5.data->>'Match'
and P5.data->>'Reference_Name' <> P1.data->>'Reference_Name'
and P5.data->>'Reference_Name' <> P2.data->>'Reference_Name'
and P5.data->>'Reference_Name' <> P3.data->>'Reference_Name'
and P5.data->>'Reference_Name' <> P4.data->>'Reference_Name'
INNER JOIN match_player_data P6
on P1.data->>'Match' = P6.data->>'Match'
and P6.data->>'Reference_Name' <> P1.data->>'Reference_Name'
and P6.data->>'Reference_Name' <> P2.data->>'Reference_Name'
and P6.data->>'Reference_Name' <> P3.data->>'Reference_Name'
and P6.data->>'Reference_Name' <> P4.data->>'Reference_Name'
and P6.data->>'Reference_Name' <> P5.data->>'Reference_Name'
INNER JOIN match_player_data P7
on P1.data->>'Match' = P7.data->>'Match'
and P7.data->>'Reference_Name' <> P1.data->>'Reference_Name'
and P7.data->>'Reference_Name' <> P2.data->>'Reference_Name'
and P7.data->>'Reference_Name' <> P3.data->>'Reference_Name'
and P7.data->>'Reference_Name' <> P4.data->>'Reference_Name'
and P7.data->>'Reference_Name' <> P5.data->>'Reference_Name'
and P7.data->>'Reference_Name' <> P6.data->>'Reference_Name'
INNER JOIN match_player_data P8
on P1.data->>'Match' = P8.data->>'Match'
and P8.data->>'Reference_Name' <> P1.data->>'Reference_Name'
and P8.data->>'Reference_Name' <> P2.data->>'Reference_Name'
and P8.data->>'Reference_Name' <> P3.data->>'Reference_Name'
and P8.data->>'Reference_Name' <> P4.data->>'Reference_Name'
and P8.data->>'Reference_Name' <> P5.data->>'Reference_Name'
and P8.data->>'Reference_Name' <> P6.data->>'Reference_Name'
and P8.data->>'Reference_Name' <> P7.data->>'Reference_Name'
INNER JOIN match_player_data P9
on P1.data->>'Match' = P9.data->>'Match'
and P9.data->>'Reference_Name' <> P1.data->>'Reference_Name'
and P9.data->>'Reference_Name' <> P2.data->>'Reference_Name'
and P9.data->>'Reference_Name' <> P3.data->>'Reference_Name'
and P9.data->>'Reference_Name' <> P4.data->>'Reference_Name'
and P9.data->>'Reference_Name' <> P5.data->>'Reference_Name'
and P9.data->>'Reference_Name' <> P6.data->>'Reference_Name'
and P9.data->>'Reference_Name' <> P7.data->>'Reference_Name'
and P9.data->>'Reference_Name' <> P8.data->>'Reference_Name'
INNER JOIN match_player_data P10
on P1.data->>'Match' = P10.data->>'Match'
and P10.data->>'Reference_Name' <> P1.data->>'Reference_Name'
and P10.data->>'Reference_Name' <> P2.data->>'Reference_Name'
and P10.data->>'Reference_Name' <> P3.data->>'Reference_Name'
and P10.data->>'Reference_Name' <> P4.data->>'Reference_Name'
and P10.data->>'Reference_Name' <> P5.data->>'Reference_Name'
and P10.data->>'Reference_Name' <> P6.data->>'Reference_Name'
and P10.data->>'Reference_Name' <> P7.data->>'Reference_Name'
and P10.data->>'Reference_Name' <> P8.data->>'Reference_Name'
and P10.data->>'Reference_Name' <> P9.data->>'Reference_Name'
Пример ввода:
{'Match':'1', 'Reference_Name":"a"}
{'Match':'1', 'Reference_Name":"b"}
{'Match':'1', 'Reference_Name":"c"}
{'Match':'1', 'Reference_Name":"d"}
{'Match':'1', 'Reference_Name":"e"}
{'Match':'1', 'Reference_Name":"f"}
{'Match':'1', 'Reference_Name":"g"}
{'Match':'1', 'Reference_Name":"h"}
{'Match':'1', 'Reference_Name":"j"}
{'Match':'1', 'Reference_Name":"k"}
{'Match':'2', 'Reference_Name":"b"}
Ожидаемый результат:
{'Match':'1', 'Reference_Name":"a"}, {'Match':'1', 'Reference_Name":"b"}, {'Match':'1', 'Reference_Name":"c"}, {'Match':'1', 'Reference_Name":"d"},{'Match':'1', 'Reference_Name":"e"}, {'Match':'1', 'Reference_Name":"f"},{'Match':'1', 'Reference_Name":"g"}, {'Match':'1', 'Reference_Name":"h"},{'Match':'1', 'Reference_Name":"j"}, {'Match':'1', 'Reference_Name":"k"}
{'Match':'2', 'Reference_Name":"b"}
Комментарии:
1. Примечание: вы можете избежать
10!
(~ 3M) перестановок результирующего набора, используя>
вместо<>
.2. @a_horse_with_no_name я добавил ввод и вывод smaple. в основном это поиск совпадающих строк и преобразование их в одну строку с 10 разными большими двоичными объектами json, каждый в своем собственном столбце
3. @wildplasser я попробовал это изменение (и, возможно, оно улучшилось), но запрос по-прежнему выполняется очень медленно (настолько медленно, что я еще не дал ему закончить)
4. @a_horse_with_no_name кстати, причина, по которой я хочу изменить формат, заключается в том, чтобы я мог считывать данные в dataframe, подобный этому: gist.github.com/jakebrinkmann/de7fd185efe9a1f459946cf72def057e
Ответ №1:
Вы можете объединить все в массив:
select jsonb_agg(data) as matches
from match_player_data
group by data ->> 'Match'
Если вам действительно нужно каждое «совпадение» в виде отдельного столбца, просто извлеките элементы из массива:
select matches -> 0 ->> 'Match' as match_number,
matches -> 0 ->> 'Reference_Name' as reference_name_1,
matches -> 1 ->> 'Reference_Name' as reference_name_2,
matches -> 2 ->> 'Reference_Name' as reference_name_3,
....
from (
select jsonb_agg(data) as matches
from match_player_data
group by data ->> 'Match'
) t
Или просто соберите имена, если вас не интересует остальное:
select match_number,
names[1] as reference_name_1,
names[2] as reference_name_2,
names[3] as reference_name_3,
....
from (
select data ->> 'Match' as match_number,
array_agg(data ->> 'Reference_Name') as names
from match_player_data
group by data ->> 'Match'
) t
Комментарии:
1. Это то, что мне нужно, спасибо. Есть ли способ использовать первый заданный вами запрос и переименовать элементы каждого поля? Полей много, поэтому переименование их всех вручную на самом деле потребует тонны работы.
2. @lexxish: нет, вам придется написать псевдоним столбца для каждого выбранного вами столбца.
3. Возможно ли повлиять на порядок, по которому «группируются» данные? Например, у меня есть столбец «Win_Status», и я бы хотел, чтобы команды-победители были сгруппированы вместе, чтобы у вас было 5 столбцов-победителей, а затем 5 столбцов-проигравших.