在 PL/PGSQL 存储过程的声明部分使用 'Case' 或 'If' 语句

Using 'Case' or 'If' statement in declaration portion of PL/PGSQL stored procedure

作为 PL/PGSQL 的新手,我正在尝试做一些在(至少一个)其他 PL/SQL 环境中有效的事情,但我无法在PL/PGSQL.

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

我已经在代码中留下了使用 CASE 和 IF 的尝试,添加注释来表示这些尝试。 我在文档中查找了 CASE 和 IF 的 SQL 版本以及 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 语句的条件部分这一目标的正确方法是什么。

第一个问题,你不能在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 名称字段视为空的,请反转 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 );