我在PostgresSQL中创建触发器。在更新时,我想比较Hstore列中的所有值并更新镜像表中的更改。我设法在变量NEW
中获取列的名称,但我无法从OLD
和CREATE OR REPLACE FUNCTION function_replication() RETURNS TRIGGER AS
$BODY$
DECLARE
k text;
BEGIN
FOR k IN SELECT key FROM EACH(hstore(NEW)) LOOP
IF NEW.k != OLD.k THEN
EXECUTE 'UPDATE ' || TG_TABLE_NAME || '_2' || 'SET ' || k || '=' || new.k || ' WHERE ID=$1.ID;' USING OLD;
END IF;
END LOOP;
RETURN NEW;
END;
$BODY$
language plpgsql;
获取值。
DECLARE @CustomerPreferredTime DATETIME = '6/10/17 09:00:00'
DECLARE @AppointmentDateTime TABLE
(
ID INT IDENTITY(1,1) PRIMARY KEY,
AppointmentTime DATETIME,
Available BIT
)
INSERT INTO @AppointmentDateTime
(AppointmentTime,Available)
VALUES
('6/10/17 08:00:00',0),
('6/10/17 08:30:00',1),
('6/10/17 09:00:00',0),
('6/10/17 09:30:00',0),
('6/10/17 10:00:00',1),
('6/10/17 10:30:00',0),
('6/10/17 11:00:00',0),
('6/10/17 11:30:00',0)
SELECT TOP 1
ROW_NUMBER() OVER (ORDER BY CASE WHEN [@AppointmentDateTime].AppointmentTime >= @CustomerPreferredTime
THEN 1
ELSE 0
END DESC, ABS(DATEDIFF(MINUTE,
@CustomerPreferredTime,
AppointmentTime))) AS ClosestAppointmentOrder,
[@AppointmentDateTime].AppointmentTime
FROM
@AppointmentDateTime
WHERE
[@AppointmentDateTime].Available = 1
AND CONVERT(DATE,AppointmentTime) = CONVERT(DATE,@CustomerPreferredTime)
ORDER BY
ClosestAppointmentOrder
答案 0 :(得分:2)
您应该对记录new
和old
的hstore表示进行操作。此外,使用format()
功能可以更好地控制和阅读。
create or replace function function_replication()
returns trigger as
$body$
declare
newh hstore = hstore(new);
oldh hstore = hstore(old);
key text;
begin
foreach key in array akeys(newh) loop
if newh->key != oldh->key then
execute format(
'update %s_2 set %s = %L where id = %s',
tg_table_name, key, newh->key, oldh->'id');
end if;
end loop;
return new;
end;
$body$
language plpgsql;
答案 1 :(得分:1)
另一个版本 - 具有极少数更新 - 部分功能设计(可能的地方)。 该触发器应该是AFTER触发器,以确保正确的行为。
CREATE OR REPLACE FUNCTION function_replication()
RETURNS trigger AS $$
DECLARE
newh hstore;
oldh hstore;
update_vec text[];
pair text[];
BEGIN
IF new IS DISTINCT FROM old THEN
IF new.id <> old.id THEN
RAISE EXCEPTION 'id should be immutable';
END IF;
newh := hstore(new); oldh := hstore(old); update_vec := '{}';
FOREACH pair SLICE 1 IN ARRAY hstore_to_matrix(newh - oldh)
LOOP
update_vec := update_vec || format('%I = %L', pair[1], pair[2]);
END LOOP;
EXECUTE
format('UPDATE %I SET %s WHERE id = $1',
tg_table_name || '_2',
array_to_string(update_vec, ', '))
USING old.id;
END IF;
RETURN NEW; -- the value is not important in AFTER trg
END;
$$ LANGUAGE plpgsql;
CREATE TABLE foo(id int PRIMARY KEY, a int, b int);
CREATE TABLE foo_2(LIKE foo INCLUDING ALL);
CREATE TRIGGER xxx AFTER UPDATE ON foo
FOR EACH ROW EXECUTE PROCEDURE function_replication();
INSERT INTO foo VALUES(1, NULL, NULL);
INSERT INTO foo VALUES(2, 1,1);
INSERT INTO foo_2 VALUES(1, NULL, NULL);
INSERT INTO foo_2 VALUES(2, 1,1);
UPDATE foo SET a = 20, b = 30 WHERE id = 1;
UPDATE foo SET a = NULL WHERE id = 1;
这段代码稍微复杂一点,但所有应该转义的内容都会被转义并减少已执行UPDATE
命令的数量。 UPDATE
是完整的SQL命令,完整SQL命令的开销应该远远高于减少完整SQL命令数量的代码。