Условие запроса, при котором значение находится в строке, разделенной запятыми

#sql #postgresql

Вопрос:

У меня есть таблица, в которой в одном из столбцов таблицы third_row хранится разделенный запятыми список чисел в виде строки, но когда его значение равно A , это означает комбинацию всех возможных чисел. Как мне подойти к этому так, чтобы запрос возвращал все строки, в которых есть third_row as A , а остальные where third_row равны одному из значений в строке, разделенной запятыми?

Для справки, вот формат таблицы:

first_row second_row third_row
0028001070200 50 A
0049048000701 51 01,04,02,31,

Я также пробовал этот запрос, но безуспешно:

 SELECT
    sds.scheme_code,
    rs.scheme_name
FROM
trea.salary_deduction_schemes sds
LEFT JOIN
trea.receipt_schemes rs
ON sds.scheme_code = rs.scheme_code
WHERE sds.list_object_head = 'A'
OR 16 IN(regexp_split_to_table(sds.list_object_head, E','))
 

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

1. Не храните данные в виде элементов, разделенных запятыми, это только вызовет у вас массу проблем.

2. Я бы предпочел использовать другую таблицу для отображения этих целых чисел, но это старый проект, который начался задолго до того, как я присоединился.

3. Это жизнь программиста, борющегося с плохими проектами других людей.

4. WHERE sds.list_object_head = 'A' or 16 = any(string_to_array(sds.list_object_head, ',')::integer[])

Ответ №1:

Ваш метод почти работает:

 WHERE sds.list_object_head = 'A' OR
      16 IN (SELECT val::int
             FROM regexp_split_to_table(sds.list_object_head, E',') val
            )
 

Вы также можете использовать сопоставление строк:

 WHERE ',' || sds.list_object_head || ',' LIKE '%,' || 16 || ',%'
 

Или вы можете преобразовать в массив и использовать операции с массивом.

Я настоятельно рекомендую найти представление, отличное от строк, для хранения целочисленных значений-предпочтительно другую таблицу или, возможно, массив.

Ответ №2:

Вы можете преобразовать список в массив и использовать = any оператор:

 WHERE sds.list_object_head = 'A' 
   OR 16 = any(string_to_array(trim(',' from sds.list_object_head), ',')::int[])
 

Это trim() необходимо для того, чтобы избавиться от трейлинга , , который после применения приведет к пустой строке string_to_array() , а это, в свою очередь, приведет к ошибке приведения, поскольку пустая строка не является допустимым целым числом.

Это, вероятно, немного быстрее, чем использовать регулярное выражение и неинвестировать массив.