Как преобразовать varchar в int [] с помощью оператора in в PostgreSQL - PullRequest
0 голосов
/ 14 июля 2020

Мне сложно по этому поводу. Я пытаюсь преобразовать varchar, содержащий список чисел, в int array, чтобы обслуживать оператор in в предложении where. Это последняя версия моего кода.

create or replace function is_product_in_categories (
    _product_id integer,
    _cat_list   varchar
)
returns boolean
as $$
declare
    _n integer;
begin
    _n = 0;

    select count(*) 
    into _n
    from category_products 
    where product_id = _product_id and category_id in (_cat_list::int[]);

  return _n > 0;
end;
$$ language plpgsql;


select is_product_in_categories(1, '1, 2, 3');

Ошибка:

 SQL Error [42883]: ERROR: operator does not exist: integer = integer[]
  Hint: No operator matches the given name and argument types. You might need to add explicit type casts.
  Where: PL/pgSQL function is_product_in_categories(integer,character varying) line 7 at SQL statement

Я пробовал несколько аргументов, например '1, 2, 3', '(1, 2, 3)' или '[1, 2, 3]'. Также удаляем круглые скобки рядом с оператором in, et c.

Есть идеи?

Ответы [ 3 ]

2 голосов
/ 14 июля 2020

Используйте string_to_array() для преобразования строки в (текстовый) массив:

SELECT string_to_array('1, 2, 3', ', ')::int[]; -- use ::int[] to cast to an int array
+---------------+
|string_to_array|
+---------------+
|{1,2,3}        |
+---------------+

Если вы управляете строкой (например, создаете ее самостоятельно), вы можете использовать любой из этих двух:

SELECT ARRAY[1, 2, 3]      -- no need to cast this one
     , '{1, 2, 3}'::int[]; -- you have to specify that it's an array, not simply a string value
+-------+-------+
|array  |int4   |
+-------+-------+
|{1,2,3}|{1,2,3}|
+-------+-------+
1 голос
/ 15 июля 2020

Измените объявление функции и определите как вариационный c целочисленный массив:

create or replace function is_product_in_categories (
    _product_id integer,
    Variadic _cat_list  integer[] )
    

или просто как массив целых чисел:

create or replace function is_product_in_categories (
_product_id integer,
_cat_list  integer[] )

В любом случае вы можете уменьшить функцию в один оператор.

create or replace function is_product_in_categories3 (
    _product_id integer,
      _cat_list integer[]
)
returns  boolean
language sql
as $$
    select 
      exists (select null 
               from category_products
              where product_id = _product_id and category_id = any(_cat_list)
             ); 
$$; 

См. здесь для полного примера обоих.

0 голосов
/ 15 июля 2020

Проблема с оператором in в том, что он не допускает массив в качестве аргумента. Вместо этого он ожидает простой список скаляров. См. Документацию PostgreSQL здесь. https://www.postgresql.org/docs/9.0/functions-comparisons.html#AEN16964

Чтобы избежать этого ограничения, комбинация = any принимает массив в качестве аргумента. Код заканчивается так.

create or replace function is_product_in_categories (
  _product_id integer,
  _cat_list   varchar
)
returns boolean
as $$
declare
  _n integer;
begin
  _n = 0;

  select count(*) 
  into _n
  from of_category_products 
  where product_id = _product_id and category_id = any (_cat_list::int[]);

  return _n > 0;
end;
$$ language plpgsql;

select is_product_in_categories(1, '{1, 2, 3}')

Кроме того, синтаксис для литеральных массивов, использующий {}, был соблюден после комментария Берги.

...