在 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 );
作为 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 );