Function to select column values by comparing against comma separated list

谁说我不能喝 提交于 2021-01-29 09:49:21

问题


I want to compare my comma delimited string with column values.

I did the following, which is not returning the expected result. ll = '"Java,CPP"' is coming dynamically.

create or replace function testing(ll text)
returns void as
$body$
Declare

       foo text[];
       ko text[];
BEGIN
       select unique_code into foo from codings
       where  unique_code = ANY (regexp_split_to_array(ll, '\,'));
       raise info '%',foo;
END;
$body$
Language plpgsql;

I got below error

ERROR:  column "Java,CPP" does not exist
LINE 1: SELECT "Java,CPP"
               ^
QUERY:  SELECT "Java,CPP"
CONTEXT:  PL/pgSQL function testing() line 8 at assignment

The value of ll is coming dynamically like above and now it is return NULL also in the row I have 'Java' and 'Cpp', both values in matching case.

select unique_code from codings;

unique_code
  Java
  Python
  CPP
  C
  Haskell

I also tried trim but not work. The updated code is here:

create or replace function testing(ll text)
returns void as
$body$
Declare

       foo text[];
       --ll text;
       ko text[];
       oo text;
BEGIN
      --oo := replace(ll,'"','');
      raise info '%',regexp_split_to_array(trim(both '"' from ll), '\,');
      ko := regexp_split_to_array(trim(both '"' from ll), '\,');

       ---ll := "CH-PREP,CH-PRMB";
       --select(regexp_split_to_array(ll, '\|')) into ko;
        --foo := array(select unique_key from membership_map);
       select  unique_code into foo from codings where  unique_code = ANY(ko);
       raise info '%',foo;
       --raise info '%', ko;
END;
$body$
Language plpgsql;

Then:

select testing('"Java,CPP"');

ERROR: malformed array literal: "Java"
DETAIL: Array value must start with "{" or dimension information
CONTEXT: PL/pgSQL function testing(text) line 16 at SQL statement

回答1:


You need to use TRIM to strip the " from your ll value:

select unique_code 
from codings 
where unique_code = ANY (regexp_split_to_array(trim(both '"' from '"Java,CPP"'), '\,'));

Output for your sample data:

unique_code
Java
CPP

SQLFiddle demo

You also have an issue in that you are assigning multiple values in one statement, for which you need to use the ARRAY operator. Change

select unique_code into foo from codings where unique_code = ANY(ko);

to

select array(select unique_code from codings where unique_code = ANY(ko)) into foo;



回答2:


You got the first error:

ERROR:  column "Java,CPP" does not exist

... for missing single quotes around your string literal in the function call. Like

SELECT testing("Java,CPP");  -- missing ''!

You probably want to trim those double quotes from the input, so the call should really be:

SELECT testing('Java,CPP');

Related:

  • Are PostgreSQL column names case-sensitive?

With the call fixed, the lurking error from a data type mismatch in the function body strikes. You try to assign unique_code text to foo text[]:

ERROR: malformed array literal: "Java" 

For example, this would work:

CREATE OR REPLACE FUNCTION testing(_ll text[])  -- taking array of text
  RETURNS text[] AS
$func$
DECLARE
   foo text[];
BEGIN
   foo := ARRAY(  -- array constructor
      SELECT unique_code 
      FROM   codings
      WHERE  unique_code = ANY(_ll)
      );

   RETURN foo;
END
$func$  LANGUAGE plpgsql;

Call:

SELECT testing('{Java,CPP}');  -- note syntax of array literal

See:

  • Pass array literal to PostgreSQL function

Passing a valid array literal also avoids the expensive and unnecessary regexp_split_to_array() call. (Regexp functions are powerful but comparatively expensive.)

Or the same as VARIADIC function:

CREATE OR REPLACE FUNCTION testing(VARIADIC _ll text[])
...  -- rest as above

You can still pass array literals (or true array values) with the keyword VARIADIC in the call:

SELECT testing(VARIADIC '{Java,CPP}'); -- with array

Or you can pass a list of element values (up to 100):

SELECT testing('Java','CPP');          -- with list of values

Related:

  • Passing multiple values in single parameter
  • Pass multiple values in single parameter
  • Return rows matching elements of input array in plpgsql function

If you absolutely must pass your string in the original form, trim() the double quotes and use the much cheaper string_to_array() instead of regexp_split_to_array():

CREATE OR REPLACE FUNCTION testing(_ll text)
  RETURNS text[] AS
$func$
DECLARE
   foo text[];
BEGIN
   foo := ARRAY(
      SELECT unique_code 
      FROM   codings
      WHERE  unique_code = ANY(string_to_array(trim(_ll, '"'), ','))
      );

   RETURN foo;
END
$func$  LANGUAGE plpgsql;

Call:

SELECT testing('"Java,CPP"'); -- even with enclosing double quotes

Aside: rather don't use a cryptic ll as parameter name. Easily misread as 11 ...



来源:https://stackoverflow.com/questions/52791715/function-to-select-column-values-by-comparing-against-comma-separated-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!