如何从函数的输入参数中导出 return 类型的列名?
How to derive a column name in the return type from input parameters to the function?
我使用 Postgres 9.5 构建了这个函数:
CREATE or REPLACE FUNCTION func_getratio_laglag(_numeratorLAG text, _n1 int, _denominatorLAG text, _n2 int, _table text)
RETURNS TABLE (date_t timestamp without time zone, customer_code text, index text, ratio real) AS
$BODY$
BEGIN
RETURN QUERY EXECUTE
'SELECT
date_t,
customer_code,
index,
(LAG('||quote_ident(_numeratorLAG)||',' || quote_literal(_n1)||') OVER W / LAG('||quote_ident(_denominatorLAG)||','|| quote_literal(_n2)||') OVER W) '
|| ' FROM ' || quote_ident(_table)
|| ' WINDOW W AS (PARTITION BY customer_code ORDER BY date_t asc);';
END;
$BODY$ LANGUAGE plpgsql;
该函数所做的就是让我能够从指定的 table 中选择 2 个不同的列,并根据不同的滞后 windows 计算它们之间的比率。要执行上面的函数,我使用以下查询:
SELECT * FROM func_getratio_laglag('order_first',1,'order_last',0,'customers_hist');
这个 returns 一个 table 带有列标签 date_t
、customer_code
、index
和 ratio
。我一直在努力研究如何将比率输出为动态列标签。也就是说,我想让它取决于输入参数,例如如果我 运行 上面的 select 查询,那么我想要列标签 date_t
、customer_code
、index
和 order_first_1_order_last_0
.
我被卡住了,有什么建议或提示吗?
How to derive a column name in the return type from input parameters to the function?
简短回答:不可能。
SQL 对列数据类型和名称非常严格。这些必须最迟在通话前或通话时宣布。没有例外。没有真正动态的列名。
我能想到 3 个中途解决方法:
1。列别名
按原样使用您的函数(或者更确切地说是我在下面建议的审核版本)并在函数调用中添加列别名:
SELECT * FROM func_getratio_laglag('order_first',1,'order_last',0,'customers_hist')
<b>AS f(date_t, customer_code, index, order_first_1_order_last_0)</b>
我会那样做。
2。列定义列表
为 return 匿名记录创建函数:
RETURNS SETOF record
然后你必须在每次调用时提供一个列定义列表:
SELECT * FROM func_getratio_laglag('order_first',1,'order_last',0,'customers_hist')
<b>AS f(date_t timestamp, customer_code text, index text, order_first_1_order_last_0 real)</b>
我会不会那样做。
3。使用注册的行类型作为多态输入/输出类型。
如果您恰好手头有行类型,这将非常有用。您 可以 通过创建一个临时 table 来即时注册行类型,但这似乎 对您的用例来说有点矫枉过正 .
本回答最后一章详解:
- Refactor a PL/pgSQL function to return the output of various SELECT queries
功能审计
使用format()
使构建查询字符串更加安全和简单。
Read the manual if you are not familiar with it.
CREATE OR REPLACE FUNCTION func_getratio_laglag(
_numerator_lag text, _n1 int
, _denominator_lag text, _n2 int
, _table regclass)
RETURNS TABLE (date_t timestamp, customer_code text, index text, ratio real) AS
$func$
BEGIN
RETURN QUERY EXECUTE format (
'SELECT date_t, customer_code, index
, (lag(%I, %s) OVER w / lag(%I, %s) OVER w) -- data type must match
FROM %s
WINDOW w AS (PARTITION BY customer_code ORDER BY date_t)'
, _numerator_lag, _n1, _denominator_lag, _n2, _table::text
);
END
$func$ LANGUAGE plpgsql;
注意 table 名称的数据类型 regclass
。这是我个人(可选)的建议。
- Table name as a PostgreSQL function parameter
旁白:我还建议不要在 Postgres 中使用大小写混合的标识符。
- Are PostgreSQL column names case-sensitive?
我使用 Postgres 9.5 构建了这个函数:
CREATE or REPLACE FUNCTION func_getratio_laglag(_numeratorLAG text, _n1 int, _denominatorLAG text, _n2 int, _table text)
RETURNS TABLE (date_t timestamp without time zone, customer_code text, index text, ratio real) AS
$BODY$
BEGIN
RETURN QUERY EXECUTE
'SELECT
date_t,
customer_code,
index,
(LAG('||quote_ident(_numeratorLAG)||',' || quote_literal(_n1)||') OVER W / LAG('||quote_ident(_denominatorLAG)||','|| quote_literal(_n2)||') OVER W) '
|| ' FROM ' || quote_ident(_table)
|| ' WINDOW W AS (PARTITION BY customer_code ORDER BY date_t asc);';
END;
$BODY$ LANGUAGE plpgsql;
该函数所做的就是让我能够从指定的 table 中选择 2 个不同的列,并根据不同的滞后 windows 计算它们之间的比率。要执行上面的函数,我使用以下查询:
SELECT * FROM func_getratio_laglag('order_first',1,'order_last',0,'customers_hist');
这个 returns 一个 table 带有列标签 date_t
、customer_code
、index
和 ratio
。我一直在努力研究如何将比率输出为动态列标签。也就是说,我想让它取决于输入参数,例如如果我 运行 上面的 select 查询,那么我想要列标签 date_t
、customer_code
、index
和 order_first_1_order_last_0
.
我被卡住了,有什么建议或提示吗?
How to derive a column name in the return type from input parameters to the function?
简短回答:不可能。
SQL 对列数据类型和名称非常严格。这些必须最迟在通话前或通话时宣布。没有例外。没有真正动态的列名。
我能想到 3 个中途解决方法:
1。列别名
按原样使用您的函数(或者更确切地说是我在下面建议的审核版本)并在函数调用中添加列别名:
SELECT * FROM func_getratio_laglag('order_first',1,'order_last',0,'customers_hist')
<b>AS f(date_t, customer_code, index, order_first_1_order_last_0)</b>
我会那样做。
2。列定义列表
为 return 匿名记录创建函数:
RETURNS SETOF record
然后你必须在每次调用时提供一个列定义列表:
SELECT * FROM func_getratio_laglag('order_first',1,'order_last',0,'customers_hist')
<b>AS f(date_t timestamp, customer_code text, index text, order_first_1_order_last_0 real)</b>
我会不会那样做。
3。使用注册的行类型作为多态输入/输出类型。
如果您恰好手头有行类型,这将非常有用。您 可以 通过创建一个临时 table 来即时注册行类型,但这似乎 对您的用例来说有点矫枉过正 .
本回答最后一章详解:
- Refactor a PL/pgSQL function to return the output of various SELECT queries
功能审计
使用format()
使构建查询字符串更加安全和简单。
Read the manual if you are not familiar with it.
CREATE OR REPLACE FUNCTION func_getratio_laglag(
_numerator_lag text, _n1 int
, _denominator_lag text, _n2 int
, _table regclass)
RETURNS TABLE (date_t timestamp, customer_code text, index text, ratio real) AS
$func$
BEGIN
RETURN QUERY EXECUTE format (
'SELECT date_t, customer_code, index
, (lag(%I, %s) OVER w / lag(%I, %s) OVER w) -- data type must match
FROM %s
WINDOW w AS (PARTITION BY customer_code ORDER BY date_t)'
, _numerator_lag, _n1, _denominator_lag, _n2, _table::text
);
END
$func$ LANGUAGE plpgsql;
注意 table 名称的数据类型 regclass
。这是我个人(可选)的建议。
- Table name as a PostgreSQL function parameter
旁白:我还建议不要在 Postgres 中使用大小写混合的标识符。
- Are PostgreSQL column names case-sensitive?