动态构建变量并在 plpgsql 函数的查询中使用它
Dynamically build a variable and use it in a query in a plpgsql function
我在 Postgres 9.6 数据库中有一个函数,我想根据收到的输入动态地将月份设置为累积。
CREATE OR REPLACE FUNCTION test(
IN p_fiscal_year integer,
IN p_month text,
IN pid integer,
IN fid integer) RETURNS TABLE(col1 text , col2 text, col3 text, col4 text, col5 text)
AS $BODY$
DECLARE user_sel_month TEXT;
BEGIN
CASE WHEN p_month ='October' Then 'October' WHEN p_month = 'November' Then '(' ||'October' || ',' || 'November' || ')' END;
RETURN QUERY select
col1,
col2,
col3,
col4,
col5
from testtable
WHERE testtable.year = p_fiscal_year
AND trim(testtable.month) IN (user_sel_month)
AND testtable.pgmid = pid
and testtable.fun_id = fid )
但我无法在 Postgres 函数中执行此操作。
它 returns 通过 'November' 时没有数据,我确实获得了 'October' 的数据。
select * from test(2016,'November',11,6);
我想动态构建变量以使其累积,因此当传递 'November' 时,我希望查询使用:
WHERE trim(testtable.month) IN ('October','November')
这里不需要动态变量 - 使用普通 SQL 代替 - 会更便宜。
尝试改变:
AND trim(testtable.month) IN (user_sel_month)
简单:
AND CASE
WHEN p_month = 'October' Then trim(testtable.month) in ('October')
WHEN p_month = 'November' Then trim(testtable.month) in ('October','November')
END
如果 p_month
的唯一允许输入是 'October' 或 'November',您可以进一步简化:
SELECT col1, col2, col3, col4, col5
FROM testtable
WHERE year = p_fiscal_year
AND (trim(month) = 'October'
OR trim(month) = 'November' AND p_month = 'November')
AND pgmid = pid
AND fun_id = fid;
但这是一个奇怪的用例。刚开始就是给猪涂口红。
不要将 year
和 month
保存为 testtable
中的 integer
和 text
。改为对月份使用单个 date
列(4 个字节)。 (更小更快,更清洁。)日期的日期部分与您的情况无关。只允许任何一天并忽略它或在 table:
中强制执行日期为“1”的日期
CREATE TABLE testtable (
fiscal_month date NOT NULL CHECK (EXTRACT('day' FROM fiscal_month) = 1)
-- more columns
);
添加的 CHECK
约束是可选的。
要像以前一样 查看 数据,请添加 VIEW
:
CREATE VIEW test_table_pretty AS
SELECT EXTRACT('year' FROM fiscal_month)::int AS year
, to_char(fiscal_month, 'Month') AS month
-- more columns
FROM testtable;
您的功能现在简单快捷:
CREATE OR REPLACE FUNCTION test(
p_fiscal_year integer,
p_month integer, -- integer!
pid integer,
fid integer)
RETURNS TABLE(col1 text, col2 text, col3 text, col4 text, col5 text) AS
$func$
SELECT t.col1, t.col2, t.col3, t.col4, t.col5
FROM testtable t
WHERE fiscal_month >= make_date(p_fiscal_year, 10 , 1) -- hard coded Oct.
AND fiscal_month < make_date(p_fiscal_year, p_month + 1, 1)
AND t.pgmid = pid
AND t.fun_id = fid;
$func$ LANGUAGE sql;
这是 实际上 累积的,因为您可以在 10 月之后的任何一个月过去(在您的示例中只剩下 12 月)。
使用 make_date()
(Postgres 9.4 或更高版本)从 integer
输入中方便地构建日期。
我在 Postgres 9.6 数据库中有一个函数,我想根据收到的输入动态地将月份设置为累积。
CREATE OR REPLACE FUNCTION test(
IN p_fiscal_year integer,
IN p_month text,
IN pid integer,
IN fid integer) RETURNS TABLE(col1 text , col2 text, col3 text, col4 text, col5 text)
AS $BODY$
DECLARE user_sel_month TEXT;
BEGIN
CASE WHEN p_month ='October' Then 'October' WHEN p_month = 'November' Then '(' ||'October' || ',' || 'November' || ')' END;
RETURN QUERY select
col1,
col2,
col3,
col4,
col5
from testtable
WHERE testtable.year = p_fiscal_year
AND trim(testtable.month) IN (user_sel_month)
AND testtable.pgmid = pid
and testtable.fun_id = fid )
但我无法在 Postgres 函数中执行此操作。
它 returns 通过 'November' 时没有数据,我确实获得了 'October' 的数据。
select * from test(2016,'November',11,6);
我想动态构建变量以使其累积,因此当传递 'November' 时,我希望查询使用:
WHERE trim(testtable.month) IN ('October','November')
这里不需要动态变量 - 使用普通 SQL 代替 - 会更便宜。
尝试改变:
AND trim(testtable.month) IN (user_sel_month)
简单:
AND CASE
WHEN p_month = 'October' Then trim(testtable.month) in ('October')
WHEN p_month = 'November' Then trim(testtable.month) in ('October','November')
END
如果 p_month
的唯一允许输入是 'October' 或 'November',您可以进一步简化:
SELECT col1, col2, col3, col4, col5
FROM testtable
WHERE year = p_fiscal_year
AND (trim(month) = 'October'
OR trim(month) = 'November' AND p_month = 'November')
AND pgmid = pid
AND fun_id = fid;
但这是一个奇怪的用例。刚开始就是给猪涂口红。
不要将 year
和 month
保存为 testtable
中的 integer
和 text
。改为对月份使用单个 date
列(4 个字节)。 (更小更快,更清洁。)日期的日期部分与您的情况无关。只允许任何一天并忽略它或在 table:
CREATE TABLE testtable (
fiscal_month date NOT NULL CHECK (EXTRACT('day' FROM fiscal_month) = 1)
-- more columns
);
添加的 CHECK
约束是可选的。
要像以前一样 查看 数据,请添加 VIEW
:
CREATE VIEW test_table_pretty AS
SELECT EXTRACT('year' FROM fiscal_month)::int AS year
, to_char(fiscal_month, 'Month') AS month
-- more columns
FROM testtable;
您的功能现在简单快捷:
CREATE OR REPLACE FUNCTION test(
p_fiscal_year integer,
p_month integer, -- integer!
pid integer,
fid integer)
RETURNS TABLE(col1 text, col2 text, col3 text, col4 text, col5 text) AS
$func$
SELECT t.col1, t.col2, t.col3, t.col4, t.col5
FROM testtable t
WHERE fiscal_month >= make_date(p_fiscal_year, 10 , 1) -- hard coded Oct.
AND fiscal_month < make_date(p_fiscal_year, p_month + 1, 1)
AND t.pgmid = pid
AND t.fun_id = fid;
$func$ LANGUAGE sql;
这是 实际上 累积的,因为您可以在 10 月之后的任何一个月过去(在您的示例中只剩下 12 月)。
使用 make_date()
(Postgres 9.4 或更高版本)从 integer
输入中方便地构建日期。