gpt4 book ai didi

PostgreSQL 触发器为多个表动态生成代码

转载 作者:行者123 更新时间:2023-11-29 11:43:58 25 4
gpt4 key购买 nike

我想为数据库中的许多表生成代码,当我准备编写“获取表 X 的代码”的第三个实现时,我停止重构我的解决方案。

我的代码是这样的:

-- Tenants receive a code that's composed of a portion of their subdomain and a unique number.
-- This number comes from this sequence.
CREATE SEQUENCE tenant_codes_seq MAXVALUE 9999 NO CYCLE;

CREATE TABLE tenants (
subdomain varchar(36) NOT NULL UNIQUE
, tenant_code char(8) NOT NULL UNIQUE
, PRIMARY KEY (tenant_code)
);

-- This function expects four parameters:
-- 1. The column that's receiving the generated code (RECEIVING_COLUMN_NAME)
-- 2. The column that's used to salt the code (SALT_COLUMN_NAME)
-- 3. The number of characters to use from the salt column (SALT_LENGTH)
-- 4. The sequence name, but defaults to RECEIVING_COLUMN_NAME || 's'
CREATE OR REPLACE FUNCTION generate_table_code() RETURNS trigger AS $$
DECLARE
receiving_column_name text;
salt_column_name text;
salt_length text;
sequence_name text;
BEGIN
receiving_column_name := TG_ARGV[0];
salt_column_name := TG_ARGV[1];
salt_length := TG_ARGV[2];

CASE
WHEN TG_NARGS = 3 THEN
sequence_name := receiving_column_name || 's';
WHEN TG_NARGS = 4 THEN
sequence_name := TG_ARGV[3];
ELSE
RAISE EXCEPTION '3 or 4 arguments expected, received %', TG_NARGS;
END CASE;

-- The intent is to return ABC-0001 when salt_column contains 'ABC'
EXECUTE 'rpad(substr(' ||
quote_ident(salt_column_name) ||
', 1, 4), 4, ' ||
quote_literal('-') ||
') || lpad(nextval(' ||
quote_literal(sequence_name) ||
')::text, ' ||
quote_literal(salt_length) ||
', ' ||
quote_literal('0') ||
')'
INTO STRICT NEW;
RETURN NEW;
END
$$ LANGUAGE plpgsql;

CREATE TRIGGER generate_tenant_code_trig
BEFORE INSERT ON tenants FOR EACH ROW
EXECUTE PROCEDURE generate_table_code('tenant_code', 'subdomain', 4);

如何分配给 NEW.tenant_code、NEW.user_code 或 NEW.table_whatever_code?

运行一些测试会产生正确的“语句”,但我似乎无法正确分配:

INSERT INTO tenants(subdomain) VALUES ('abc')


CREATE TABLE
ERROR: syntax error at or near "NEW"
LINE 1: NEW.tenant_code := rpad(substr(subdomain, 1, 4), 4, '-') || ...
^
QUERY: NEW.tenant_code := rpad(substr(subdomain, 1, 4), 4, '-') || lpad(nextval('tenant_codes')::text, '4', '0'::text)
CONTEXT: PL/pgSQL function "generate_table_code" line 20 at EXECUTE statement

最佳答案

我会非常热衷于被证明是错误的(我自己偶尔也需要这个),但据我所知,使用变量引用列名是您实际上需要使用 PL/C 触发器的情况之一比 PL/PgSQL 触发器。您会在 contrib/spi 和 PGXN 上找到此类触发器的示例。

或者,为您的列命名一致,以便能够直接引用它们,例如NEW.tenant_code

就个人而言,我通常最终会编写一个创建触发器的函数:

create function create_tg_stuff(_table regclass, _args[] text[])
returns void as $$
begin
-- explore pg_catalog a bit
execute $x$
create function $x$ || quote_ident(_table || '_tg_stuff') || $x$()
returns trigger as $t$
begin
-- more stuff
return new;
end;
$t$ language plpgsql;
$x$;
end;
$$ language plpgsql;

关于PostgreSQL 触发器为多个表动态生成代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6392942/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com