Изменение странного запроса Mysql на Postgresql, который использует group_concat
Я перемещаю нашу внутреннюю базу данных из mysql в postgres и в процессе переноса всех наших старых запросов / функций. Большинство из них тривиально, но сегодня я столкнулся с тем, что заставляет меня чесать голову. Вот:
UPDATE
k_coderound AS cr, k_coderound AS cr_m
SET
cr.is_correct = IF(
(SELECT GROUP_CONCAT(option_id ORDER BY variable_id) AS `values` FROM k_value
WHERE code_round_id=cr.id GROUP BY code_round_id) =
(SELECT GROUP_CONCAT(option_id ORDER BY variable_id) AS `values` FROM k_value
WHERE code_round_id=cr_m.id GROUP BY code_round_id),
1,
0
)
WHERE
cr.is_master=0
AND cr_m.is_master=1
AND cr_m.object_id=cr.object_id
AND cr_m.content_type_id =cr.content_type_id
Я знаю, что у Postgres нет group_concat, и вместо этого следует использовать array_agg. Моя проблема в том, что я не могу точно понять, что происходит - этот запрос был написан давным-давно кем-то, кого больше нет с нами. Сложность также осложняется отсутствием оператора IF в Postgres. Если кто-то может дать отзыв или совет, я буду очень признателен!
1 ответ
Трудно сказать, что это за намерение. Мой подход заключается в том, чтобы сначала найти оператор SELECT, который возвращает "целевые" данные.
Что-то вроде этого:
select cr.is_correct,
array_agg(case when kv1.code_round_id = cr.id then kv1.option_id else null end, ',' order by kv1.variable_id) as kv_values1,
array_agg(case when kv2.code_round_id = cr_m.id then kv2.option_id else null end, ',' order by kv2.variable_id) as kv_values2
from k_coderound cr
join k_value kv1 on kv1.code_round_id = cr.id
join k_coderound cr_m
on cr_m.object_id=cr.object_id
and cr_m.content_type_id =cr.content_type_id
join k_value kv2 on kv2.code_round_id = cr_m.id
where cr.is_master=0
and cr_m.is_master=1
Это, скорее всего, не правильно, но я думаю, что это показывает, как нестандартные выражения MySQL могут быть переведены в стандартный SQL (и, следовательно, в PostgreSQL)
Как только это, кажется, делает правильную вещь, я бы обернул это в утверждение UPDATE:
update k_coderound cru
set cr.is_correct = case
when t.kv_values1 = t.kv_values2 then 1
else 0
end
from (select cr.ctid,
array_agg(case when kv1.code_round_id = cr.id then kv1.option_id else null end, ',' order by kv1.variable_id) as kv_values1,
array_agg(case when kv2.code_round_id = cr_m.id then kv2.option_id else null end, ',' order by kv2.variable_id) as kv_values2
from k_coderound cr
join k_value kv1 on kv1.code_round_id = cr.id
join k_coderound cr_m
on cr_m.object_id=cr.object_id
and cr_m.content_type_id =cr.content_type_id
join k_value kv2 on kv2.code_round_id = cr_m.id
where cr.is_master=0
and cr_m.is_master=1
) t
where t.ctid = cru.ctid
Я почти уверен, что пропустил некоторые синтаксические вещи, но, надеюсь, это поможет вам начать.