#postgresql
#postgresql
Вопрос:
У меня есть один столбец в моей базе данных, qs5
который содержит ряд вариантов множественного выбора 1-4, которые могут отображаться в любом случайном порядке, разделенных пробелом, например 1 2 4
или 4 1
Я хочу извлечь каждый из этих параметров в отдельный столбец, чтобы у меня были результирующие столбцы qs5c1
— qs5c4
, чтобы приведенные выше примеры выглядели как
|qs5c1|qs5c2|qs5c3|qs5c4|
|-----|-----|-----|-----|
| 1 | 2 |null | 4 |
| 1 |null |null | 4 |
Это SQL, который я использовал
substring('1' from position('1' in qs5) for 1) as qs5c1,
substring('2' from position('2' in qs5) for 1) as qs5c2,
substring('3' from position('3' in qs5) for 1) AS qs5c3,
substring('4' from position('4' in qs5) for 1) AS qs5c4
Но то, с чем я возвращаюсь, используя приведенные выше данные в качестве примера, это то, где он просто выбирает первый символ в строке и пропускает остальные.
|qs5c1|qs5c2|qs5c3|qs5c4|
|-----|-----|-----|-----|
| 1 |null |null |null |
|null |null |null | 4 |
Я думаю, что когда он извлекает первый символ, длина qs5
на 1 символ меньше, чем было ранее, но опять же, это не объясняет, почему вторая строка пропускает 1, поскольку 1 должен быть в том же месте до / после извлечения 4.
Спасибо!
Ответ №1:
Проблема в том, что вы не substring()
из qs5
, а из литералов '1'
, '2'
и т.д. поэтому, конечно, это может привести только к этому единственному символу в литерале. Если вы используете qs5
вместо этого, это работает так, как вы задумали.
SELECT substring(qs5 FROM position('1' IN qs5) FOR 1) qs5c1,
substring(qs5 FROM position('2' IN qs5) FOR 1) qs5c2,
substring(qs5 FROM position('3' IN qs5) FOR 1) qs5c3,
substring(qs5 FROM position('4' IN qs5) FOR 1) qs5c4
FROM elbat;
Ответ №2:
Если это действительно фиксированный набор значений, я бы сделал это так:
select case when '1' = any(string_to_array(qs5, ' ')) then '1' end as qs51,
case when '2' = any(string_to_array(qs5, ' ')) then '2' end as qs52,
case when '3' = any(string_to_array(qs5, ' ')) then '3' end as qs53,
case when '4' = any(string_to_array(qs5, ' ')) then '4' end as qs54,
case when '5' = any(string_to_array(qs5, ' ')) then '5' end as qs55
from the_table;
Онлайн-пример:https://rextester.com/FMR86051
Если вам нужно это более динамичным способом, вы можете использовать что-то вроде этого:
select f.options[1] as qs5c1,
f.options[2] as qs5c2,
f.options[3] as qs5c3,
f.options[4] as qs5c4
from the_table t
cross join lateral (
select array_agg(x.val order by g.idx) as options
from generate_series(1,4) g(idx)
left join unnest(string_to_array(t.qs5, ' ')::int[]) with ordinality as x(val,idx) on g.idx = x.val
) f
;
Онлайн-пример с 8 элементами:https://rextester.com/PMKDW38472
Комментарии:
1. итак, на самом деле это 8, я просто сократил до 4 ради этого примера. как вы думаете, с 8 все будет в порядке?
2. @ClayCrosby: да, вы можете сделать то же самое для 8 значений. Я добавил более общее (но более сложное) решение для сопоставления элементов с правильным индексом столбца.