使用'案例'或者'如果' PL / PGSQL存储过程的声明部分中的语句

时间:2018-03-29 18:09:08

标签: function if-statement plpgsql postgresql-9.3 case-statement

作为PL / PGSQL的新手,我正在尝试做一些适用于(至少一个)其他PL / SQL环境的东西,而且我还没有能够在PL / PGSQL中分离出这样做的方法。

我正在创建一个函数,并将一个变量传递给函数。使用此变量,我构建(或留空)一个变量,然后将其包含在最终的SQL语句中,然后执行该语句。

我已经尝试在代码中使用CASE和IF添加注释来表示尝试。 我查阅了文档,其中列出了CASE和IF的CAS版本以及CASE和IF的PL / PGSQL版本,但我无法确定它们之间的差异和正确使用,当然,是否我试图使用它的方式是允许的,或者如何正确地实现它。

--DROP FUNCTION public._1_ExampleQuery(varchar);

CREATE OR REPLACE FUNCTION public._1_ExampleQuery(namefield varchar(50) DEFAULT 'name')
RETURNS TABLE(id double precision , name character varying(100), frc smallint) 
  LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
-- ------ GOAL ------------------------------------------------------------- 
--
--  If 'namefield' is blank, set namedwhere as empty, if namefield is 
--  present build sql structure to omit blanks

-- ------ Attempt using CASE ----------------------------------------------- 
--
--  CASE namefield
--      WHEN '' THEN
--          namedwhere varchar(50) := '';
--      ELSE 
--          namedwhere varchar(50) := ' and ' || namefield || ' <> '''' ';
--  END CASE;

-- ------ Attempt using If  ------------------------------------------------ 
--
--  IF namefield = '' THEN
--      namedwhere varchar(50) := '';
--  ELSE 
        namedwhere varchar(50) := ' and ' || namefield || ' <> '''' ';
--  END IF;
-- ---------------------------------------------------------------------------

sqlQuery varchar(500) := 'SELECT id,name,frc FROM road_nw WHERE frc = 1 ' || namedwhere;

BEGIN
    -- RAISE NOTICE 'SQL Query Statement: %',sqlQuery;
    RETURN QUERY EXECUTE sqlQuery;
END;

当我取消注释CASE部分时,我收到此错误:

ERROR:  syntax error at or near "CASE"
LINE 10:  CASE namefield
          ^
SQL state: 42601
Character: 480

当我取消注释IF部分时,我得到了类似的错误:

ERROR:  syntax error at or near "IF"
LINE 17:  IF namefield = '' THEN
          ^
SQL state: 42601
Character: 752

我使用的PostgreSQL版本是: 在x86_64-unknown-linux-gnu上的PostgreSQL 9.3.19,由gcc编译(Ubuntu 4.8.4-2ubuntu1~14.04.3)4.8.4,64位

总而言之,可以在函数的声明部分使用CASE和IF,如果是这样的话怎么样?如果他们不能,那么实现具有SQL语句的条件部分的目标的正确方法是什么。

1 个答案:

答案 0 :(得分:0)

第一个问题,你不能在DECLARE部分使用case-endcase或if-then-else-endif。

第二个问题是SQL注入。

另请注意,varchar与文本相同,只是(略微)慢。

我添加了RETURNS NULL ON NULL INPUT,因为null会导致错误。

并添加了quote_identifier来阻止SQL注入

CREATE OR REPLACE FUNCTION public._1_ExampleQuery(namefield varchar(50) DEFAULT 'name')
RETURNS TABLE(id double precision , name character varying(100), frc smallint) 
  LANGUAGE 'plpgsql'
  RETURNS NULL ON NULL INPUT
AS $BODY$
DECLARE
-- ------ GOAL ------------------------------------------------------------- 
--
--  If 'namefield' is blank, set namedwhere as empty, if namefield is 
--  present build sql structure to omit blanks

  sqlQuery text;
  namedwhere text;
BEGIN

  IF namefield = '' THEN
     namedwhere := '';
  ELSE 
     namedwhere := ' and ' || quote_identifier(namefield) || ' <> '''' ';
  END IF;

  sqlQuery  := 'SELECT id,name,frc FROM road_nw WHERE frc = 1 ' || namedwhere;

    -- RAISE NOTICE 'SQL Query Statement: %',sqlQuery;
    RETURN QUERY EXECUTE sqlQuery;
END;
$BODY$;

如果你想将null namefield视为空,则反转if,并删除RETURNS NULL ON NULL INPUT

另一种方法是使用CASE ... END表达式而不是变量。 (这里我将null视为空白)

RETURN QUERY EXECUTE (  'SELECT id,name,frc FROM road_nw WHERE frc = 1 '
  || CASE WHEN namefield <> '' 
      THEN ' and ' || quote_identifier(namefield) || ' <> '''' ' 
      ELSE ''
     END );