Joh*_*ohn 3 postgresql auto-increment dynamic-sql plpgsql
如何使用字符串和DECLARE
变量的组合动态引用序列名称(如下所示)?下面的代码是否正确或者是否有其他方法可以做到这一点?
DO
我的目标是出于性能原因在/块中执行此操作BEGIN
,而且它将通过做一些有用的事情来帮助我理解 plpgsql,因此除非确实必须,否则我不会将其混合到 PHP 中。
DO $$
DECLARE PKEY VARCHAR;
BEGIN
SELECT pg_attribute.attname INTO PKEY
FROM pg_index, pg_class, pg_attribute
WHERE pg_class.oid = 'parts1'::regclass
AND indrelid = pg_class.oid
AND pg_attribute.attrelid = pg_class.oid
AND pg_attribute.attnum = any(pg_index.indkey)
AND indisprimary;
--SELECT setval('parts1_id_seq', (SELECT MAX(pkey) + 1 FROM parts));
SELECT setval('parts1_' || PKEY || '_seq', (SELECT MAX(pkey) + 1 FROM parts));
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
你自己提到过,你刚刚开始使用 Postgres。然而,您正在立即处理极其高级的任务,处理系统目录并使用高级动态 SQL 进行操作以实现自动化。
虽然您的目标看起来很合理,但您仍然需要从基础开始。这里需要解释的东西太多了。从优秀手册(的相关部分)开始。我在下面提供了一些深层链接。
要获取主键中涉及的列的名称(和数据类型),请使用以下更简单的查询:
SELECT a.attname, format_type(a.atttypid, a.atttypmod) AS data_type
FROM pg_index i
JOIN pg_attribute a ON a.attrelid = i.indrelid
AND a.attnum = ANY(i.indkey)
WHERE i.indrelid = 'tbl'::regclass
AND i.indisprimary;
Run Code Online (Sandbox Code Playgroud)
我更新了Postgres Wiki 页面,您的原始查询似乎源自该页面。
但是,这可以返回多行,而您只分配一个值。假设您已经确定我们正在处理serial
类型(单列)主键。否则,请使用我之前的答案中列出的类似技术来确定。
然后使用专用的系统信息函数pg_get_serial_sequence()
来确定所使用序列的名称,如我之前的答案中所示。
根据文档:
serial
获取,smallserial
或bigserial
列使用的序列名称
DO
$do$
BEGIN
EXECUTE (
SELECT format($$SELECT setval('%s'::regclass, max(%I)) FROM %s$$
, pg_get_serial_sequence(a.attrelid::regclass::text, a.attname)
, a.attname
, a.attrelid::regclass
)
FROM pg_index i
JOIN pg_attribute a ON a.attrelid = i.indrelid
AND a.attnum = i.indkey[0]
WHERE i.indrelid = 'tbl'::regclass
AND i.indisprimary
);
END
$do$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
这将构建并执行以下形式的查询:
SELECT setval('tbl_tbl_id_seq'::regclass, max(tbl_id)) FROM tbl;
Run Code Online (Sandbox Code Playgroud)
这是高级的东西,不太适合初学者。如果您不确切知道自己在做什么,那么搞乱系统目录可能很快就会失败。
在 Postgres 和 plpgsql 中坚持使用合法的全小写标识符,让您的生活更轻松。但永远不要在动态 SQL 中依赖它,因为动态 SQL 中您还需要始终防御 SQL 注入。
大量使用来format()
方便、安全地构建查询字符串。
在 plpgsql 函数中,SELECT
如果不分配结果就无法调用。你会用PERFORM
它来代替。手册中有详细说明。
我完全删除了它,因为我将所有内容都简化为一个EXECUTE
.
由于整个操作仅对单列主键有意义,因此我将JOIN
条件简化为a.attnum = i.indkey[0]
Note that pg_index.indkey
has thespecial (internal) type int2vector
。与 Postgres 数组不同,它的索引从0开始,而不是 1。
养成在 plpgsql 代码(包括DO
语句)周围使用带有标记的美元引号的习惯。这允许像我在示例中所做的那样嵌套简单的美元引号。细节:
你在这里只需要一个SELECT
:
SELECT setval('tbl_tbl_id_seq'::regclass, max(tbl_id)) FROM tbl;
Run Code Online (Sandbox Code Playgroud)
代替:
SELECT setval('tbl_tbl_id_seq'::regclass, (SELECT max(tbl_id) FROM tbl));
Run Code Online (Sandbox Code Playgroud)SQL Fiddle演示了一些事情。
归档时间: |
|
查看次数: |
1888 次 |
最近记录: |