我正在使用 Postgres 8.3 数据库并尝试使用 PL/pgSQL 创建函数,该函数根据输入到表中的日期生成表名:
我必须创建一系列按日期索引的表,例如:
drop table one_day_11_13 cascade;
create table one_day_11_13 as
select * from master_table where
timestamp < '2012-11-14' and timestamp >= '2012-11-13';
drop table one_day_11_14 cascade;
create table one_day_11_14 as
select * from master_table where
timestamp < '2012-11-15' and timestamp >= '2012-11-14';
我在想做到这一点的方法是创建一个 PL/pgSQL 函数作为参数 ('11_13', '2012-11-14', '2012-11-13')
例如创建上面的第一个表。我在编写适当的 EXECUTE 语句时遇到问题。
做这种事情的最好方法是 PL/pgSQL 矫枉过正?
最佳答案
首先,考虑升级到更新的版本。 8.3 is on its way out.
对于 8.3,它可以像这样工作:
CREATE OR REPLACE FUNCTION f_recreate_tbl(date, date)
RETURNS void AS
$func$
DECLARE
-- derive tablename from first date
_tbl text := 'one_day_' || to_char($1, 'MM_YY');
BEGIN
-- Use IF EXISTS to avoid an exception when table does not exist.
EXECUTE
'DROP TABLE IF EXISTS ' || _tbl || ' CASCADE';
EXECUTE
'CREATE TABLE ' || _tbl || ' AS
SELECT *
FROM master_table
WHERE timestamp >= ''' || $1::text || '''::date
AND timestamp < ''' || $2::text || '''::date';
END
$func$ LANGUAGE plpgsql;
调用:
SELECT f_recreate_tbl('2012-11-13'::date, '2012-11-14'::date);
每当您想要参数化标识符时,都不能使用纯 SQL。使用
EXECUTE
PL/pgSQL 函数中的动态 SQL 或DO
statement (版本 9.0+)。这个版本足够安全。使用更灵活的输入,您将不得不使用
quote_ident()
andquote_literal()
清理标识符和值以防止可能的 SQL 注入(inject)。在现代版本(自 8.4 起)中,您将使用
USING
跳过将参数转换为文本的子句。不要使用
timestamp
作为列名。它是一种数据类型的名称。使用
DROP TABLE
IF EXISTS
。 Already available in 8.3.我从日期派生表名并跳过第三个参数。看起来像是一种简化。
关于sql - 参数化表名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13805714/