PostgreSQL 存储过程 一、前言 最近在实习期间遇到的一些问题,其实逻辑思路很简单,就是需要把关联表的一些脏数据清除,逻辑就是从原表获得所有id,再根据这个id去关系表中遍历所有数据,根据关系表中的数据进行判断更新。
理想的 sql 如下:
1 2 3 4 5 6 7 update dt_app_user_rel r2set r2.is_delete= 1 where r2.range_type= 2 and r2.data_key not in ( select r1.data_key from dt_app_user_rel r1 where r1.app_id= r2.app_id and r1.range_type= 1 and r1.is_delete= 0 )
这过程中存在单表的自查询和更新,但这种情况是不被允许的,这个时候就需要用到存储过程了。
这里先附上存储过程的简单结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 create or replace procedure public.proc_check_data(check_period character )language 'plpgsql' AS $BODY$ declare dept_name varchar (128 ); begin end ; $BODY$;
其实会发现相当于只是把好几段 sql 放在一起,中间可以引入一些公共变量,从而完成一些靠单句查询无法完成的工作。
存储过程的优点除了这个,最重要的是可以重复使用,从而可以减少数据库开发人员的工作量。
第二个则是存储过程可以提高性能。存储过程在创建的时候就进行了编译,将来使用的时候不用再重新编译。一般的SQL语句每执行一次就需要编译一次,所以使用存储过程提高了效率。
回到我们之前的问题,那么在依靠存储过程后,sql 如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 CREATE OR REPLACE PROCEDURE "public"."process_dt_app_user_rel"() AS $BODY$ DECLARE done BOOLEAN := FALSE ; app_id_val INT ; cur CURSOR FOR SELECT DISTINCT app_id FROM dt_app_user_rel; BEGIN CREATE TEMPORARY TABLE temp_data_keys (data_key varchar (255 )); OPEN cur; LOOP FETCH cur INTO app_id_val; EXIT WHEN NOT FOUND; INSERT INTO temp_data_keys SELECT data_key FROM dt_app_user_rel WHERE range_type = 1 AND is_delete = 0 AND app_id = app_id_val; UPDATE dt_app_user_rel SET is_delete = 1 WHERE range_type = 2 AND app_id = app_id_val AND data_key NOT IN ( SELECT data_key FROM temp_data_keys ); TRUNCATE TABLE temp_data_keys; END LOOP; CLOSE cur; DROP TABLE IF EXISTS temp_data_keys; END ;$BODY$ LANGUAGE plpgsql
最后这段 sql 编译后,就可以重复使用了,避免了下次脏数据清理时重复编写 sql。