PostgreSQL 在对账|购票|防纂改|原子操作中的语法妙用

标签

PostgreSQL , update , returning , NEW , OLD


背景

在数据库中更新记录时,有时为了对账,或者防纂改的目的,需要在更新后立即返回更新前和更新后的值。

例如以set bit为例,假设使用BIT串作为火车的每个位置,每个BIT代表一张票,0表示未售卖,1表示已售卖。

购票时,使用set bit=1的操作,为了确保不出现重复售票的问题,必须确保被set的value以前的值为0,SET后的值为1。

这个动作其实也可以在function中来保证,不过你要扩展FUNCTION的功能,在function中确保set bit前的值为0,set bit后的值为1。

本文要讲的是通过update returning语法来实现类似的对照功能。

其实insert returning也有类似的用法,例如插入时并不知道数据库生成了什么UUID,这个UUID可能是流水号,将来程序要用来做二次确认的搜索。(如运营商的二次确认,或者短信密码,也需要用来作为标识)

update returning语法

目前PostgreSQL支持insert,delete,update的returning。

insert returning 返回的是新插入的值。

delete returning 返回的是被删除的值。

update returning 返回的是更新后的值,不能返回更新前的值,但是有方法可以得到。

或者等阿里云RDS PostgreSQL退出update returning old.column的功能吧。

例子

PostgreSQL 支持delete, update返回删除前的值以及更新后的值.

postgres=# create table test (old text, new text, mod_time timestamp);
CREATE TABLE
postgres=# insert into test values ('old', 'new', now());
INSERT 0 1
postgres=# select * from test ;
 old | new |          mod_time
-----+-----+----------------------------
 old | new | 2013-01-22 15:36:02.543393
(1 row)

postgres=# update test set new='DIGOAL', old=new, mod_time=clock_timestamp() returning *;
 old |  new   |          mod_time
-----+--------+----------------------------
 new | DIGOAL | 2013-01-22 15:36:40.062419
(1 row)
UPDATE 1

update returning 返回的是更新后的值.

postgres=# select * from test ;
 old |  new   |          mod_time
-----+--------+----------------------------
 new | DIGOAL | 2013-01-22 15:36:40.062419
(1 row)

postgres=# delete from test returning *;
 old |  new   |          mod_time
-----+--------+----------------------------
 new | DIGOAL | 2013-01-22 15:36:40.062419
(1 row)
DELETE 1

delete returning 返回的是删除前的值.

returning 后的子句类似select ... from 中的子句, 所以也支持表达式 :

postgres=# insert into test values ('old', 'new', now());
INSERT 0 1
postgres=# update test set new='DIGOAL', old=new, mod_time=clock_timestamp() returning 1,2,3,old,new,mod_time,old||new;
 ?column? | ?column? | ?column? | old |  new   |          mod_time          | ?column?
----------+----------+----------+-----+--------+----------------------------+-----------
        1 |        2 |        3 | new | DIGOAL | 2013-01-22 15:39:13.238924 | newDIGOAL
(1 row)
UPDATE 1

update returning 如何返回old.column

方法1, update 中, 如果将一个字段的值赋予给另一个字段, 那会将更新前的值赋予给它, 而不是更新后的值.

postgres=# update test set new='DIGOAL', old=new, mod_time=clock_timestamp() returning 1,2,3,old,new,mod_time,old||new;
 ?column? | ?column? | ?column? | old |  new   |          mod_time          | ?column?
----------+----------+----------+-----+--------+----------------------------+-----------
        1 |        2 |        3 | new | DIGOAL | 2013-01-22 15:39:13.238924 | newDIGOAL
(1 row)
UPDATE 1

new='DIGOAL', old=new

更新后 :   

old = 'new' (new字段更新前的值)
new = 'DIGOAL'

使用这种方法可以返回set_bit前的bit string以及set_bit后的bit string。

方法2, 如果被更新的表有PK,可以使用update from子句, 返回旧值

UPDATE tbl x
SET    tbl_id = 23
     , name = 'New Guy'
FROM   tbl y                -- using the FROM clause
WHERE  x.tbl_id = y.tbl_id  -- must be unique
AND    x.tbl_id = 3
RETURNING y.tbl_id AS old_id, y.name AS old_name
        , x.tbl_id          , x.name;
Returns:

 old_id | old_name | tbl_id |  name
--------+----------+--------+---------
  3     | Old Guy  | 23     | New Guy

UPDATE tbl x
SET    tbl_id = 24
     , name = 'New Gal'
FROM  (SELECT tbl_id, name FROM tbl WHERE tbl_id = 4 FOR UPDATE) y
WHERE  x.tbl_id = y.tbl_id
RETURNING y.tbl_id AS old_id, y.name AS old_name, x.tbl_id, x.name;

使用这种方法也可以返回set_bit前的bit string以及set_bit后的bit string。

参考

1. http://www.postgresql.org/docs/9.2/static/sql-delete.html

2. http://www.postgresql.org/docs/9.2/static/sql-update.html

3. http://stackoverflow.com/questions/7923237/return-pre-update-column-values-using-sql-only-postgresql-version

时间: 2024-09-14 21:02:07

PostgreSQL 在对账|购票|防纂改|原子操作中的语法妙用的相关文章

PostgreSQL update returning NEW|OLD column value 在对账|购票|防纂改|原子操作中的妙用

标签 PostgreSQL , update , returning , NEW , OLD 背景 在数据库中更新记录时,有时为了对账,或者防纂改的目的,需要在更新后立即返回更新前和更新后的值. 例如以set bit为例,假设使用BIT串作为火车的每个位置,每个BIT代表一张票,0表示未售卖,1表示已售卖. 购票时,使用set bit=1的操作,为了确保不出现重复售票的问题,必须确保被set的value以前的值为0,SET后的值为1. 这个动作其实也可以在function中来保证,不过你要扩展F

PostgreSQL Oracle 兼容性之 - 如何篡改插入值(例如NULL纂改为其他值)

Oracle有个功能,可以将用户插入的NULL值替换成指定的值. 这个功能和default值的用意并不一样,default是指用户没有指定值时,使用default值代替. 例如 postgres=# alter table test alter column id set default 1; ALTER TABLE postgres=# create table t(id int, info text default 'abc'); CREATE TABLE postgres=# insert

又闹事!伊拉克黑客Pro_Mast3r纂改了特朗普竞选网站的子域名

本文讲的是又闹事!伊拉克黑客Pro_Mast3r纂改了特朗普竞选网站的子域名,特朗普自从参与竞选以来,一直话题不断,尤其是有关网络安全的话题更是令人不安.近日又有报道称,一个来自伊拉克的黑客组织"Pro_Mast3r"于上周日(2月19日)攻击了其竞选筹款网站donaldjtrump.com.据悉,该网站托管在secure2.donaldjtrump.com上,由Cloudflare内容管理和安全平台进行管理. 网站并不是直接由其竞选筹款网站donaldjtrump.com链接过来的,

Mozilla 封杀纂改安全设置的流行 Firefox 扩展

上周日,Firefox用户向bugzilla报告了流 行扩展YouTube Unblocker的可疑行为--安装之后,杀毒软件立即报警有第三方下载,并将下载的程序归类为恶意程序.这位用户在研究了YouTube Unblocker的代码发现它会安装一个新的user.js配置文件改变用户的默认设置,关闭内置的扩展签名功能,允许安装非签名扩展.在扩展签名功能 关闭之后,YouTube Unblocker会从第三方网站下载了一个被杀毒软件归类恶意程序的扩展Adblock Converter.YouTub

数据库案例集锦 - 开发者的《如来神掌》

背景 「剑魔独孤求败,纵横江湖三十馀载,杀尽仇寇,败尽英雄,天下更无抗手,无可柰何,惟隐居深谷,以雕为友.呜呼,生平求一敌手而不可得,诚寂寥难堪也.」 剑冢中,埋的是剑魔独孤求败毕生几个阶段中用过的几柄剑: 利剑无意:第一柄是青光闪闪的利剑,凌厉刚猛,无坚不摧,弱冠前以之与河朔群雄争锋. 软剑无常:第二柄是紫薇软剑,三十岁前所用,误伤义士不祥,悔恨不已,乃弃之深谷. 重剑无锋:第三柄是玄铁重剑,重剑无锋,大巧不工,四十岁之前恃之横行天下. 木剑无俦:第四柄是已腐朽的木剑. 无剑无招:四十岁后,不

数据库选型十八摸 之 PostgreSQL - 致 架构师、开发者

标签 PostgreSQL , 数据库特性 , 数据库应用场景分析 , 数据库选型 背景 数据库对于一家企业来说,相比其他基础组件占据比较核心的位置. 有很多企业由于最初数据库选型问题,导致一错再错,甚至还有为此付出沉痛代价的. 数据库的选型一定要慎重,但是这么多数据库,该如何选择呢? 我前段时间写过一篇关于数据库选型的文章,可以参考如下 <数据库选型思考> 另外,PostgreSQL这个数据库这些年的发展非常的迅猛,虽然国内还跟不上国外的节奏,但是相信国人逐渐会融合进去. 所以我专门针对Po

PostgreSQL flashback(闪回) 功能实现与介绍

标签 PostgreSQL , 脏读 , 事务 , flashback , 闪回 , drop , truncate , dml 背景 闪回的需求往往是救命的需求,因为通常情况下数据库正常运行是不需要闪回的,往往是出现了误操作,被攻击,被注入后,数据库的数据被删除或恶意纂改并且纂改的事务已提交,也就是说纂改已经被持久化了. 这种情况下需要闪回来救命,回到被破坏前的状态. 闪回的目标分为两种: DML闪回和DDL闪回. DML闪回指对INSET, UPDATE, DELETE操作的闪回.DDL闪回

PostgreSQL 可靠性分析 - 关于redo block原子写

PostgreSQL 可靠性分析 - 关于redo block原子写 作者 digoal 日期 2016-10-11 标签 PostgreSQL , redo , redo block 原子写 , 可靠性分析 背景 PostgreSQL 可靠性与大多数关系数据库一样,都是通过REDO来保障的. 群里有位童鞋问了一个问题,为什么PostgreSQL的REDO块大小默认是8K的,不是512字节. 这位童鞋提问的理由是,大多数的块设备扇区大小是512字节的,512字节可以保证原子写,而如果REDO的块

防火防盗防篡改,驱动人生6帮您抵制恶意软件

当电脑里被误装了恶意软件,这些恶意软件会在用户不知情的情况下对驱动文件进行破坏和篡改,导致各种的驱动问题,实在令人很头疼.那么,我们该如何避免因电脑里的驱动文件被破坏和纂改而导致的各类驱动问题呢?让驱动人生6的"驱动保护"功能解决您的烦恼,全面保护您的驱动文件不受破坏! 在驱动人生6的界面右侧,我们可以看到"驱动保护"功能图标,点击"驱动保护"图标,进入到"驱动保护"界面,点击驱动实时保护即可,驱动人生6会即时将您电脑里相关设