在使用PostgreSQL 9.3后端的网页游戏中,我有时必须禁止用户,将它们放入下表:
create table pref_ban (
id varchar(32) primary key,
first_name varchar(64),
last_name varchar(64),
city varchar(64),
last_ip inet,
reason varchar(128),
created timestamp default current_timestamp
);
我通过运行以下程序禁止用户,以便他/她在下次登录时无法进入游戏(即不会立即禁止违规者):
create or replace function pref_delete_user(_id varchar,
_reason varchar) returns void as $BODY$
begin
insert into pref_ban --THIS FAILS WITH "duplicate key"
(id, first_name, last_name, city, last_ip, reason)
select id, first_name, last_name, city, last_ip, _reason
from pref_users where id = _id;
create temporary table temp_gids (gid int not null) on commit drop;
insert into temp_gids (gid) select gid from pref_scores where id=_id;
delete from pref_games p
using temp_gids t
where p.gid = t.gid;
create temporary table temp_rids (rid int not null) on commit drop;
insert into temp_rids (rid) select rid from pref_cards where id=_id;
delete from pref_rounds r
using temp_rids t
where r.rid = t.rid;
delete from pref_users where id=_id;
end;
$BODY$ language plpgsql;
但是,上述过程中的INSERT语句有时会失败:
SQLSTATE[23505]: Unique violation: 7 ERROR: duplicate key value violates unique constraint "pref_ban_pkey" DETAIL: Key (id)=(GC1121680399) already exists.
CONTEXT: SQL statement "insert into pref_ban (id, first_name, last_name, city, last_ip, reason) select id, first_name, last_name, city, last_ip, _reason from pref_users where id = _id" PL/pgSQL function pref_delete_user(character varying,character varying) line 4 at SQL statement
当我在第一次禁用用户之后写了一些游戏统计数据时会发生这种情况(因为用户不会立即被禁止,游戏统计数据有时仍会被写入数据库)。
这对我来说没问题,但我想知道,我怎么能忽略INSERT失败?
我知道通常以下“UPSERT”方案正在与PostgreSQL一起使用:
update pref_ban set
first_name = _first_name,
last_name = _last_name,
city = _city,
last_ip = _last_ip,
...
where id = _id;
if not found then
insert into pref_ban(id,
first_name,
last_name,
city,
last_ip,
...)
values (_id,
_first_name,
_last_name,
_city,
_last_ip,
...
now());
end if;
但这不是我在此之后所说的:因为我不需要更新被禁止的用户详细信息。我只想退出INSERT失败的程序。