PostgreSQL INSERT INTO ON CONFLICT语法。UPSERT(insert on conflict do) 记录存在就更新,不存在就更新。 在某些业务场景中,需要把插入语句和更新组合到一起,一条SQL同时完成插入和更新逻辑。 这个时候就需要用到 INSERT ON CONFLICT
语法特性了。可以实现根据主键或者唯一约束,来插入或指定条件更新。
官方语法说明 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Command: INSERT Description: create new rows in a table Syntax: [ WITH [ RECURSIVE ] with_query [, ...] ] INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ] { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query } [ ON CONFLICT [ conflict_target ] conflict_action ] [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ] where conflict_target can be one of : ( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) [ WHERE index_predicate ] ON CONSTRAINT constraint_name and conflict_action is one of : DO NOTHING DO UPDATE SET { column_name = { expression | DEFAULT } | ( column_name [, ...] ) = ( { expression | DEFAULT } [, ...] ) | ( column_name [, ...] ) = ( sub- SELECT ) } [, ...] [ WHERE condition ]
假如我们有这样一张日志表,要同时实现写入和更新。
1 2 3 4 5 6 7 8 9 CREATE TABLE user_log_info ( log_id text NOT NULL , log_name text, log_path text, log_size bigint , log_time timestamp , create_time timestamp , PRIMARY KEY (log_id,log_time) )
根据主键新增或更新
符合写入日志时间比当前记录新,才执行写入更新
1 2 3 4 5 6 7 8 9 10 11 INSERT INTO user_log_infoVALUES ( 'demo001' , 'open1' , '/logs/a.log' , 30 , TO_TIMESTAMP( 1713509590 ), LOCALTIMESTAMP ) ON CONFLICT ( log_id, log_time ) DO UPDATE SET log_name = EXCLUDED.log_name, log_path = EXCLUDED.log_path, log_size = EXCLUDED.log_size, log_time = EXCLUDED.log_time, create_time = EXCLUDED.create_time WHERE EXCLUDED.log_time > user_log_info.log_time
根据符合条件才更新
举例:符合日志size大小,比之前大才会更新,SQL如下
1 2 3 4 5 6 7 8 9 10 11 INSERT INTO user_log_infoVALUES ( 'demo001' , 'open1' , '/logs/a.log' , 30 , TO_TIMESTAMP( 1713509590 ), LOCALTIMESTAMP ) ON CONFLICT ( log_id, log_time ) DO UPDATE SET log_name = EXCLUDED.log_name, log_path = EXCLUDED.log_path, log_size = EXCLUDED.log_size, log_time = EXCLUDED.log_time, create_time = EXCLUDED.create_time WHERE EXCLUDED.log_size > user_log_info.log_size
实际应用场景 相当于我们在写入数据时,可以像写查询一样 带上WHERE条件,实现符合条件才更新
PGSQL定时任务实现 cron + pgpass 利用shell脚本 + Linux定时任务,去定时执行清理日志表
首先配置命令行免密登录 根据Postgres的官方文档配置.pgpass。
文件内容格式如下:127.0.0.1:5432:库名:用户:密码
1 2 3 4 5 6 7 8 9 登录服务器,在用户主目录中创建`.pgpass`文件配置 vi .pgpass 127.0.0.1:5432:demo_test:postgres:123456 // 授权当前用户可见 chmod 600 .pgpass// 执行验证测试,查询连接用户数SQL /usr/pgsql-13/bin/psql -h 127.0.0.1 -p 5432 -d demo_test -U postgres -c "select COUNT(*) from pg_stat_activity"
编写shell脚本封装SQL vim pgcron.sh。文件内容如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/bin/bash execpgsql (){ echo $1 starttime=`date +"%Y-%m-%d %H:%M.%S" ` result=$(/usr/pgsql-13/bin/psql -h 127.0.0.1 -p 5432 -d demo_test -U postgres -c "$1 " ) endtime=`date +"%Y-%m-%d %H:%M.%S" ` echo "[开始执行:$starttime " "执行结束:$endtime ]" "SQL:$1 " "结果:$result " } sql="DROP TABLE user_log_info" execpgsql "$sql "
再将这个脚本加入 crontab,并设定执行周期