我有一个通用的键/值表,我想在函数中对其进行预处理以按键进行过滤,然后根据键来命名值。
该表是这样的,其中id
指向另一个表(但是出于这个问题的目的,无关紧要):
CREATE TABLE keyed_values (id INTEGER, key TEXT, value TEXT, PRIMARY KEY(id, key));
INSERT INTO keyed_values(id, key, value) VALUES
(1, 'x', 'Value for x for 1'),
(1, 'y', 'Value for y for 1'),
(2, 'x', 'Value for x for 2'),
(2, 'z', 'Value for z for 2');
等等。键值可以变化,并且并非所有ID都将使用相同的键。
具体地说,我想做的是创建一个函数,该函数将生成与给定键匹配的行。然后,它将为每个与key
命名为并带有键的匹配value
返回一行。
因此,给定键名自变量'x'
的函数的输出将与执行此命令的结果相同:
SELECT id, value x FROM keyed_values WHERE key = 'x';
id | x
----+-------------------
1 | Value for x for 1
2 | Value for x for 2
(2 rows)
这是我的刀路,将其他一些答案汇总在一起:
CREATE FUNCTION value_for(key TEXT) RETURNS SETOF RECORD AS $$
BEGIN
RETURN QUERY EXECUTE format('SELECT id, value %I FROM keyed_values WHERE key = %I', key, key);
END;
$$ LANGUAGE 'plpgsql';
该功能被接受。但是当我执行它时,出现了这个错误:
SELECT * FROM value_for('x');
ERROR: a column definition list is required for functions returning "record"
LINE 1: SELECT * FROM value_for('x');
我了解到它在告诉我什么,但没有解决方法。如何动态定义输出列名称?
答案 0 :(得分:1)
key
子句中使用的WHERE
不是标识符,而是文字,因此该函数应类似于:
CREATE FUNCTION value_for(key TEXT) RETURNS SETOF RECORD AS $$
BEGIN
RETURN QUERY EXECUTE format('SELECT id, value %I FROM keyed_values WHERE key = %L', key, key);
END;
$$ LANGUAGE plpgsql;
如果已将函数定义为返回记录数据类型,则必须存在一个别名或关键字AS,然后是形式为column_name data_type [,...]的列定义列表。列定义列表必须匹配该函数返回的实际列数和类型。
使用列定义列表:
SELECT * FROM value_for('x') AS (id int, x text);
请注意,您不需要动态SQL或plpgsql,因为列名是在上面的列表中定义的。简单的SQL函数应该更快一些:
CREATE OR REPLACE FUNCTION value_for(_key text)
RETURNS SETOF RECORD AS $$
SELECT id, value
FROM keyed_values
WHERE key = _key
$$ LANGUAGE SQL;
如果您不喜欢被迫向每个函数调用添加列定义列表,则可以从函数返回表:
CREATE OR REPLACE FUNCTION value_for_2(_key text)
RETURNS TABLE(id int, x text) AS $$
SELECT id, value
FROM keyed_values
WHERE key = _key
$$ LANGUAGE SQL;
SELECT * FROM value_for_2('x');
id | x
----+-------------------
1 | Value for x for 1
2 | Value for x for 2
(2 rows)
但是,这不能解决问题。无法动态定义从函数返回的列名。在执行查询之前,必须指定返回列的名称和类型。