从包含列名的变量引用记录的列

时间:2013-01-03 19:09:52

标签: postgresql plpgsql dynamic-sql

plpgsql 语言的函数中,并且具有:

  1. "col" CHARACTER VARYING = 'a';(可'b'
  2. "rec" RECORD;保存来自:(SELECT 1 AS "a", 2 AS "b")
  3. 的记录
  4. "res" INTEGER;
  5. 我需要从"col"引用"rec"中的指定列。因此,如果"col"'b',我会引用"rec"."b",然后将其值保存到"res"

1 个答案:

答案 0 :(得分:3)

您无法在plpgsql中按名称引用匿名记录类型的列。即使您在SELECT语句中的示例中拼出列别名,这些只是噪音并被丢弃。

如果要按名称引用记录类型的元素,则需要使用众所周知的类型。创建并使用类型:

CREATE TYPE my_composite_type(a int, b int);

或使用与任何现有表关联的行类型。您可以将表名称写为数据类型。

DECLARE
   rec my_composite_type;
...

然后,您需要条件语句动态SQL 才能使用"col"作为标识符。

条件声明:

IF col = 'a' THEN
   res := rec.a;
ELSIF col = 'b' THEN
   res := rec.b;
ELSE
   RAISE EXCEPTION 'Unexpected value in variable "col": %', col;
END IF;

对于两种可能的情况,这就是要走的路 或动态SQL:

EXECUTE 'SELECT $1.' || col
INTO res
USING rec;

我在这里看不到问题,但要注意使用动态SQL的SQL注入。如果col可以保存任意数据,则需要使用quote_ident() or format()

对其进行转义

演示

使用动态SQL演示更强大但更棘手的变体。

快速&用于创建(临时!)已知类型进行测试的脏方法:

CREATE TEMP TABLE rec_ab(a int, b int);

功能:

CREATE OR REPLACE FUNCTION f_test()
  RETURNS integer AS
$func$
DECLARE
    col   text := 'a';  -- can be 'b'
    rec   rec_ab;
    res   int;
BEGIN
    rec := '(1, 2)'::rec_ab;

    EXECUTE 'SELECT $1.' || col
    INTO res
    USING rec;

    RETURN res;
END
$func$
  LANGUAGE plpgsql VOLATILE;

呼叫:

SELECT f_test();

返回:

f_test
----
1