工作中的一些sql小结(postgresql)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_31156277/article/details/83578733

工作中的遇到的一些postgresql总结。

一、子查询

子查询中,使用到的子查询关键字 exists 最多。基本格式如下:

SELECT... 
FROM tablename 
WHERE ... and exists (
			SELECT id FROM tablename where ...)

1.1 应用场景

在CRM系统中,批量删除排班,但要求这些排班没有被使用。

-- 先将符合条件的排班都查询出来。
SELECT aw.id 
FROM pmm_arrangework  aw
WHERE  date >= CURRENT_DATE
AND NOT EXISTS 
(
  SELECT sr.signid 
  FROM pmm_signrecord sr 
  WHERE sr.arrangeworkid = aw.id 
)

一般不推荐使用NOT INNOT IN 遇到 NULL 可能不安全。


二、批量表操作

企业中,常常需要做数据抽取工作,然后定时进行调度。这个时候,批量插入表,批量更新表就十分常见。

  • truncate table 表名
    如果删除整个表,使用truncatedelete 更好。(序列重置、速度、事务等角度对比)
truncate table pmm_

但,如果只删除部分,则必须使用delete

DELETE FROM pmm_statistic WHERE reportmonth = '2018-11'

  • 批量插入数据
--INSERT INTO TABLENAME(...) SELECT ...
INSERT INTO pmm_statistic (userid,reportmonth,saleareaid,plandatenum,actualdatenum,planworkhours,actualhours,latenum,
latehours,leaveearlynum,leaveearlyhours,notsignnum,nianjia,tiaoxiujia,bingjia,shijia,hunjia,
chanjia,peichanjia,parentid) 
SELECT u.userinfoid,to_char(now(),'YYYY-MM'),u.orgstructid,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,m.parentid 
FROM  userinfo u
INNER JOIN account app ON u.userinfoid = app.userinfoid
INNER JOIN struct m ON app.memberid = m.orgstructid
WHERE u.platstatus = 1 AND m.platstatus = 1 and app.platstatus = 1 AND app.appcode = 'pmm';
  • 批量更新
-- 业务场景:安人员id分组统计这个月这个月的应出勤工时。然后进行批量更新。
UPDATE pmm_statistic SET  planworkhours = v.planworkhours
FROM (
SELECT userinfoid, sum(planworkhours) AS planworkhours
FROM pmm_signresult s
WHERE  s.workdate >= thismonthbegin and  s.workdate  < nextmonthbegin
AND s.platstatus = 1
GROUP BY s.userinfoid
)v 
WHERE v.userinfoid = pmm_statistic.userid AND pmm_statistic.reportmonth = thismonth;

三、case when 应用

  • case when
-- 大致格式
case when …… THEN ……  when …… THEN …… ELSE …… END AS 字段名称

case when 常常用于判断类型,通过不同的类型输出不同的值。例如:通过case when 判断上班的打卡类型。是签到还是签退;订单的类型等等。

SELECT s.collectdate,sd.productname,
CASE WHEN  sd.approvalstatus = 1 THEN '待确认' ELSE '已确认' END AS statusname
FROM pmm_salesreport s 
  • 和其他聚合函数一起使用

业务场景:按照人进行分组;汇总每个人各种请假类型的总时间,然后批量更新统计表中
案例一:

UPDATE bi_pmm_kq_statistic SET nianjia = v.nianjia,tiaoxiujia=v.tiaoxiujia,bingjia=v.bingjia,
shijia=v.shijia,hunjia=v.hunjia,chanjia=v.chanjia,peichanjia=v.peichanjia	
FROM(SELECT 
	SUM (CASE WHEN leavetype = '1' THEN timespan ELSE 0 END ) AS nianjia,
	SUM (CASE WHEN leavetype = '2' THEN timespan ELSE 0 END ) AS tiaoxiujia,
	SUM (CASE WHEN leavetype = '3' THEN timespan ELSE 0 END ) AS bingjia,
	SUM (CASE WHEN leavetype = '4' THEN timespan ELSE 0 END ) AS shijia,
	SUM (CASE WHEN leavetype = '5' THEN timespan ELSE 0 END ) AS hunjia,
	SUM (CASE WHEN leavetype = '6' THEN timespan ELSE 0 END ) AS chanjia,
	SUM (CASE WHEN leavetype = '7' THEN timespan ELSE 0 END ) AS peichanjia,
	userinfoid
	FROM pmm_leave l
	WHERE starttime >= thismonthbegin AND endtime < nextmonthbegin
	 AND l.approvalstatus = '2'
	GROUP BY userinfoid
 )v
WHERE v.userinfoid = pmm_statistic.userid AND pmm_statistic.reportmonth = thismonth;


案例二:

-- 多个条件判断
SELECT
CASE WHEN (cc.status = 1 AND cp.type = 1) THEN 0
WHEN (cc.status IS NULL AND cp.type = 1) THEN NULL
ELSE 1 END AS flag
FROM plan AS cp
LEFT JOIN  customer AS cc ON cp.id = cc.coid

case when在很多情景下都是比较好用的。


案例三:
在案例一中,其实思想就是行转列的操作。在sqlserver 中有透视函数(PIVOT); 在pg中有crosstab ;

案例描述:
在这里插入图片描述

CREATE TABLE sales
(
  year integer, -- 年
  month integer, -- 月
  counts integer -- 销量
)
WITH (
  OIDS=FALSE
);
ALTER TABLE sales
  OWNER TO postgres;
COMMENT ON TABLE sales
  IS '销售报表';
COMMENT ON COLUMN sales.year IS '年';
COMMENT ON COLUMN sales.month IS '月';
COMMENT ON COLUMN sales.counts IS '销量';
insert into sales values(1991,1,11),(1991,2,12),(1991,3,13),(1991,4,14),(1992,1,21),(1992,2,22),(1992,3,23),(1992,4,24);
-- 方式一:
select year AS,
sum(case when month = 1 THEN counts ELSE 0 END) AS 一月,
sum(case when month = 2 THEN counts ELSE 0 END) AS 二月,
sum(case when month = 3 THEN counts ELSE 0 END) AS 三月,
sum(case when month = 4 THEN counts ELSE 0 END) AS 四月
from sales
GROUP BY year
order by year ASC;
---方式二:
SELECT s.year AS,
(SELECT sum(t.counts) FROM  sales AS t WHERE t.month = '1' AND s.year = t.year) AS 一月,
(SELECT sum(t.counts) FROM  sales AS t WHERE t.month = '2' AND s.year = t.year) AS 二月,
(SELECT sum(t.counts) FROM  sales AS t WHERE t.month = '3' AND s.year = t.year) AS 三月,
(SELECT sum(t.counts) FROM  sales AS t WHERE t.month = '4' AND s.year = t.year) AS 四月
FROM sales AS s GROUP BY s.year ORDER BY s.year;

四、rank() over(partition by … order by …)

分组排序。取前多少条记录。

业务场景: 一天有多个排班,每个排班都需要打签到签退卡;每次进入打卡页面(多个排班,页签切换),每个排班,需要显示签到的第一次打卡,签退的最后一次打卡。
每个排班的签到签退可以打卡多次。

思路:签到类型分组;签到签退按时间升序、降序;然后获取第一条数据。

SELECT * FROM(
SELECT userid,workplanid,signtype,recorddate,signdatetime,
rank() over(PARTITION BY signtype,workplanid ORDER BY signdatetime ASC) AS rownumber
FROM pmm_signrecord
WHERE recorddate = CURRENT_DATE
AND userid = 1001
AND signtype = 1  
) r
WHERE rownumber = 1

SELECT * FROM(
SELECT userid,workplanid,signtype,recorddate,signdatetime,
rank() over(PARTITION BY signtype,workplanid ORDER BY signdatetime DESC) AS rownumber
FROM pmm_signrecord
WHERE recorddate = CURRENT_DATE
AND userid = 1001
AND signtype = 2  
) r
WHERE rownumber = 1

开窗函数 overgroup by的区别。开窗函数更便捷;group by 也可以做到相同的效果,但是group by 不方便的地方在于,select后的字段必须出现在group by 后面或者需要使用聚合函数。如果要使用额外的字段,常常需要再嵌套一个子查询。

当然开窗函数还有更多的使用方法; 如分页、排名等等。


五、 pg 函数(其他数据称为:存储过程)

SELECT from produrcename()– 调用函数
perform produrcename – 执行,可以在一个函数中调用另外一个函数

CREATE OR REPLACE FUNCTION  过程名(参数名 参数类型,..) 
RETURNS 返回值类型 as
$body$
--声明变量
DECLARE 
变量名变量类型 
-- 例如:flag Boolean;
--变量赋值方式(变量名类型 :=值)
BEGIN
-- 主体内容
return 变量名;
END	
$body$
LANGUAGE plpgsql;

注: 语法中有 replace 关键字,如果函数名已经存在,可能被覆盖,所以创建时用create;如果需要修改则使用replace


在编写函数时,常常需要打印一些字段的值,这个时候可以使用下面语法:

--raise的语法为:

raise notice 'param is %',param;

六、PostgreSQL自动增加

PostgreSQL拥有的数据类型smallserialserialbigserial,这些都不是真正的类型,但仅仅是一个概念上的便利,为创建唯一标识符列。这些都是相似到支持AUTO_INCREMENT属性其他一些数据库。

CREATE TABLE COMPANY (
	ID SERIAL PRIMARY KEY,
	NAME TEXT NOT NULL,
	AGE INT NOT NULL,
	ADDRESS CHAR (50),
	SALARY REAL
);

在这里插入图片描述

关于postgresql中的数据类型,可以查看这边文章:https://www.cnblogs.com/kungfupanda/p/4478917.html


其他

  • upset 处理冲突
    插入数据时,可能会出现主键冲突等。当发生冲突事件时,需要采取补充措施。

  • 数据抽样
    针对大量的数据,可能需要抽取随机的几条的数据,这个时候可以使用下面两个函数:
    systembernoull


扩展

有兴趣可以阅读该文章 PostgreSQL 与 MySQL 相比,优势何在?

猜你喜欢

转载自blog.csdn.net/qq_31156277/article/details/83578733