每种数据库都有自己的特色,SQL SERVER 也有自己的招数,timestamp字段类型会针对于行中任何列值的变化,而改变,之前也写过PG 怎么来模拟这个功能
https://blog.csdn.net/liuhuayang/article/details/106682052
看看自己以前写的,青涩了。上一篇提到了,软实力的建设,终究数据库不光是备份,高可用架构,以及内核研究,你要服务的应用程序到底怎么能更用好数据库的功能是另一个赛道。
PG中的Generated Columns 是基于PG12 后添加的,生成列主要的功能在于简化数据的获取,可以将部分SQL的撰写变得更加的简单。我们从简单的开始,直到怎么能模拟 SQL SERVER timestamp 字段的独有功能。
我们提供 actor 表作为源对象
然后我们将数据灌入到 actor_copy 表中,然后查看表,可以看到多了一列并且这一列实际上是 first_name 和 last_name 的组合。那么name 这一列到底是怎么生成的。
create table actor_copy
(id int,
first_name varchar(20),
last_name varchar(20),
last_update timestamp,
name varchar(40) GENERATED ALWAYS AS (first_name ||' ' || last_name) stored);
其中name 就是一个生成列,通过生成列将表中的字段 first_name 和 last_name 两个字段结合,生成新的字段name. 在查询时就不需要 在语句中拼接两个字段。
当然看上去好像也没有什么用,我们看下一个例子,表payment 中 amount 记录这每次顾客付出的租金,而实际上如果要计算一个扣除税的金额,并加载到表中就比较麻烦了。
Alter table payment add column after_tax numeric(10,2) GENERATED ALWAYS AS (amount - 1) stored;
在添加这一列后,可以看到我们的列中已经有了相关的数字。查询SQL的时候后续就可以直接引用这一列,并且这一列会随着amount的变化而变化。
生成列本身可以利用场景会比较多,看你怎么玩,甚至可以写一个函数,将加载到这一列的值先进行函数的计算,然后落表。
下面进入主题,很多业务场景都希望在一次事务操作行后任意列的值是否变化并判断这行是否变化了。应用场景有很多,举例客户点单,然后客户在完成订单后,会改变这个订单所在行的某列,或某几列的信息
之前类似SQL SERVER 的TimeSTAMP 就可以完成这个功能,任何一列的值变化,都会自动触发timestamp 字段的值变化, SQL SERVER 中的timestamp 并不是一个时间字段,而是一段二进制码。这个功能在 MYSQL 或ORACLE 都没有。
大部分的思路想要模拟还是通过触发器来在数据update 后,更新字段的值来完成判断。
但PG可以抛弃trigger 的方式或rule的方式,通过 PG12 加入的生成列来完成这个功能。
这里我们用film 表做一个事例
1 添加generated 行,其中对于title 和 description 的字段合并后,进行md5的运算,然后将这个值存储在 sqlserver_timestamp 字段。
2 我们随便找一行,然后更改其中的值
3 我们比对在修改前 sqlserver_timestamp 字段的值的变化
4 OK 没有问题
下面的命令就是添加这个功能在这个表,title 或者 description 两个字段的值进行更改后,通过类似sql server timestamp功能来判断这一行的两个字段值变化了。
alter table film add column sqlserver_timestamp text GENERATED ALWAYS AS (md5(coalesce(title,'1') || coalesce(description,'1') )) stored;
经过比对后,的确值是变化了,哪怕你只改变一个字母,甚至你加入一个空格,都会改变值。
此时应用程序就很简单的继续使用类似SQL SERVER 的功能,
1 在处理事务前,通过查询将修改的条件行中的sqlserver_timestamp 行的值记录到缓存中
2 执行事务
3 查询film表中的 sqlserver_timestamp 行的值,与之前的值是否有变化
变化就是证明这两个字段的值一个或两个都变化了,否则就是没有改变。
这样就能证明事务执行的成功或失败,或者更新中那些行的改变值和原来的值是一致的,那些不是。
这个功能还是比较有用的,好处就是彻底和笨拙的 trigger 或 rule 说拜拜。
当然这里留了一个问题,为什么要通过coalesce 来对字段进行处理,直接计算不是更快?WHY
PG 功能还是很强大的,只要愿意动脑,大多数时候开发提出的需求,我们都可以说 sure, no problem. 至少PG 不是一个数据存储容器,而是数据处理的单元,维度不同,高度不同。