pgsql 使用技巧

1.CASCADE 级联删除,如果表或模式或数据库有序列、分区相关 依赖时,需要修改表或模式或数据库,则使用它

DROP SCHEMA viid_facestatic  CASCADE

2.pgsql隐藏字段ctid,一般用于去重

pgsql 使用技巧_第1张图片

pgsql 使用技巧_第2张图片

3. pg 表自连接使用场景

3.1 有一张卡口表 求距离A卡口L米的所有卡口ID

pgsql 使用技巧_第3张图片

pgsql 使用技巧_第4张图片

-- 查询以卡口ID为1为圆心,半径为100米 范围内的其他卡口信息
SELECT a.tollgate_name,a.longitude,a.latitude,b.tollgate_name,b.longitude,b.latitude 
FROM tollgate a JOIN tollgate b
ON a.tollgate_id <>b.tollgate_id
AND 2 * asin(sqrt(power(sin((a.latitude * pi()/180.0-b.latitude * pi()/180.0) / 2), 2) + cos(a.latitude * pi()/180.0) * cos(b.latitude * pi()/180.0) * power(sin((a.longitude * pi()/180.0 - b.longitude * pi()/180.0)/2),2)))*6378.137*1000 <= 100
WHERE a.tollgate_id=1 

3.2 使用自连接替代lead(a,1),lead(a,2),lead(a,3)......

场景:已知字段 商品名,年,月,销售额,求累计的销售额

即已知:

pgsql 使用技巧_第5张图片

求:

pgsql 使用技巧_第6张图片

代码:

--
SELECT*from public.sp;
--
SELECT s_id,year,a_month,a_money,array_agg(month),sum(money) from
(
select a.s_id,a.year,a.month as a_month,a.money as a_money,b.month,b.money from public.sp a 
INNER JOIN public.sp b
on a.s_id=b.s_id
where a.year=b.year and b.month<=a.month
)a GROUP BY a.s_id,a.year,a_month,a_money;

3.3 使用自连接 实现滑动窗口

已知:

pgsql 使用技巧_第7张图片

求:如果某人在10s,在大于等于2个酒店被抓拍到,则认为该人短时间内在多个宾馆登记开房-判断为疑似组织卖淫人员,要求筛选出组织卖淫证据(记录)

SELECT *FROM (
--5. 关联原表 获取每个窗口的抓拍详情,如果一个人在同一个批次的同一个酒店被抓拍多次,则去重只保留该酒店第一次的抓拍记录
SELECT b.*,a.cnt,a.rn as time_batch_id,row_number()over(PARTITION by b.name,b.jdname,a.rn ORDER BY b.recordtime) min_rn  FROM (
--4. 为去重后的每人在每个窗口的结果指定一个统一的批次id
SELECT a.*,ROW_NUMBER()over(partition by null order by a.recordtime,a.name) as rn FROM (
SELECT a.* FROM (
--3. 去掉窗口子集(即一个窗口完全属于另一个窗口,则去掉该窗口)
SELECT a.* ,ROW_NUMBER()over(partition by a.name,a.real_etime ORDER BY a.real_stime) dis_rn FROM (
--2.计算各个窗口内酒店的个数,并得到每个窗口中第一条和最后一条数据的时间
WITH  a  as (
--1. 为每条记录分配一个窗口,窗口大小为10s
SELECT *,recordtime as s_time,recordtime+10 as e_time FROM (SELECT id,name,age,jdname,recordtime as rtime,EXTRACT(epoch FROM TIMESTAMPtz(recordtime)) as recordtime from
 test1)a
 )SELECT a.id,a.name,a.recordtime,a.rtime,
a.s_time,a.e_time,min(b.recordtime) real_stime,max(b.recordtime) real_etime,count(DISTINCT b.jdname) as cnt
FROM a INNER JOIN a as b
on  a.name=b.name  and b.s_time BETWEEN a.s_time AND a.e_time 
GROUP BY a.id,a.name,a.recordtime,a.rtime,
a.s_time,a.e_time
-- 2.1过滤出酒店个数大于指定个数的窗口
HAVING count(DISTINCT b.jdname)>=2
)a)a WHERE a.dis_rn=1)a)a
INNER JOIN (SELECT id,name,age,jdname,recordtime as rtime,EXTRACT(epoch FROM TIMESTAMPtz(recordtime)) as recordtime from
 test1) b
ON a.name=b.name  AND b.recordtime BETWEEN a.real_stime AND a.real_etime
)a WHERE a.min_rn=1
order by a.recordtime,a.name;

结果:一个批次ID对应一个滑动窗口

pgsql 使用技巧_第8张图片

3. pg序列的创建场景

创建主键的自增序列:

CREATE SEQUENCE viid_facestatic.resource_id_seq INCREMENT 1 START 1 MINVALUE 1

4.pg系统表的使用场景

4.1 系统表:information_schema.tables

场景1:扫描出该数据库下的满足某种条件的一个或者多个表

例子: 假设该库下有表名为:table_201901,table_201902,table_201903.....table_2019012 的12张表,这12张表 表结构相同

需求:对table_201901到table_201907这几张表 的数据 做某个逻辑处理

实现:

select table_schema||'.'||table_name as table_name 
from information_schema.tables 
where table_type = 'BASE TABLE' 
and table_name >= 'face_archive_201901' 
and table_name <=  'face_archive_201907' ;

5.pg系统字段的使用场景(ctid去重)

6. pg json字段处理与递归查询

场景1:求所有采集设备 所属的社区 的社区名称

pgsql 使用技巧_第9张图片

pgsql 使用技巧_第10张图片

sql

--递归从设备找到其所属社区
-- 字段:resource 表示设备ID
  SELECT a.s_resource,a.e_resource,a.resource_name,a.s_entry_exit::text::INTEGER
 FROM(
  with RECURSIVE le (e_resource,resource_name,parent_resource,jsontext,s_entry_exit,s_resource,depath) as 
 (
  select resource as e_resource,resource_name,parent_resource,jsontext,jsontext->'entry_exit'  as s_entry_exit,resource as s_resource,1 AS depath from viid_facestatic.resource
  union all
  select e2.resource as e_resource,e2.resource_name,e2.parent_resource,e2.jsontext,e3.s_entry_exit,e3.s_resource,e3.depath+1
      from resource e2,le e3 where e3.parent_resource=e2.resource
 )
 select  le.e_resource,le.resource_name,le.s_entry_exit,le.jsontext,s_resource,depath
 from le WHERE le.jsontext::json->>'ctype'='社区' )a;

----------------------------------------------------------------------
 SELECT a.s_resource,a.e_resource,a.resource_name,a.s_entry_exit
 FROM(
  with RECURSIVE le (e_resource,resource_name,parent_resource,jsontext,s_entry_exit,s_resource,depath) as 
 (
  select resource as e_resource,resource_name,parent_resource,jsontext,jsontext->'entry_exit'as s_entry_exit,resource as s_resource,1 AS depath from resource WHERE resource='50011200001191000012'
  union all
  select e2.resource as e_resource,e2.resource_name,e2.parent_resource,e2.jsontext  ,e3.s_entry_exit,e3.s_resource,e3.depath+1
      from resource e2,le e3 where e3.parent_resource=e2.resource
 )
 select  le.e_resource,le.resource_name,le.s_entry_exit,le.jsontext,s_resource,depath
 from le WHERE le.jsontext::json->>'ctype'='社区' )a;
----------------------------------------------------------------------
--json转text再转integer:le.s_entry_exit::text::INTEGER
--  (b.jsontext->''entry_exit'')::text::INTEGER as entry_exit
-- 查看是否转换成功:pg_typeof(le.s_entry_exit::text::INTEGER)

查询结果

pgsql 使用技巧_第11张图片

7. json强制类型转换只能直接转text,再转其他类型

SELECT a.*,b.longitude,b.latitude,b.name,(b.jsontext->'entry_exit')::text::INTEGER as entry_exit FROM tablename1 a INNER JOIN viid_facestatic.device b ON
a.device_id1 = b.ape_id


SELECT (value::jsonb->>'iscs_person')::jsonb->>'name' as name,jsonb_array_elements((value::jsonb->>'iscs_house')::jsonb)->>'address' as address,*  FROM "archive_info" 
where value::jsonb->>'datatype' ='iscs_person' or value::jsonb->>'datatype' ='iscs_house'

8. pg中按某一个或其中几个字段去重,只保留第一条

pgsql 使用技巧_第12张图片

pgsql 使用技巧_第13张图片

9.获取字段为json或者jsono类型的里面的key,value

10. 时间转换

10.1 字符串日期 与数字时间 互转

-- 无时区差(精确到秒),如果精确到毫秒 数字需要*1000
SELECT EXTRACT(epoch FROM cast('2019-08-01 00:00:02' AS TIMESTAMPTZ)),to_char(to_TIMESTAMP(1564588802),'yyyy-MM-dd HH24:MI:SS');

-- 有时区差
SELECT EXTRACT(epoch FROM cast('2019-08-01 00:00:02' AS TIMESTAMP)),to_char(to_TIMESTAMP(1564617602),'yyyy-MM-dd HH24:MI:SS');

-- cast()转为非整点,且+8
SELECT EXTRACT(epoch FROM cast('2019-08-01 00:00:02' AS TIMESTAMP));
-- date()转为整点的数字,且+8
-- 下面两个结果一样的
SELECT EXTRACT(epoch FROM date('2019-08-01 00:00:00'));
SELECT EXTRACT(epoch FROM date('2019-08-01 00:00:02'));
-- cast()转为非整点,且不+8
SELECT EXTRACT(epoch FROM cast('2019-08-01 00:00:02' AS TIMESTAMPTZ));

11. 通过两个点的经纬度计算两点间的距离

--发一:直接使用公式 ,计算结果单位为公里 

select abs(6371.004 * acos(sin(纬度1) *sin(纬度2) * cos(经度1 - 经度2) +cos(纬度1) * cos(纬度2)) * acos(-1) / 180) as distance

--法二:需要在pg中安装一个插件,然后使用以下公式
 SELECT
 ST_Distance(
    ST_SetSRID(ST_MakePoint(a.longitude,a.latitude),4326)::geography,
   ST_SetSRID(ST_MakePoint(a.leadlongitude,a.leadlatitude),4326)::geography
  )as distance

-- 发三:计算结果为单位米(推荐)
2 * asin(sqrt(power(sin((a.latitude * pi()/180.0-a.leadlatitude * pi()/180.0) / 2), 2) + cos(a.latitude * pi()/180.0) * cos(a.leadlatitude * pi()/180.0) * power(sin((a.longitude * pi()/180.0 - a.leadlongitude * pi()/180.0)/2),2)))*6378.137*1000 as distance

12.where 后用case when

SELECT id,name
FROM kx_customer
WHERE 1 = 1
AND CASE
WHEN customertype = 1 THEN
    saleareaid = 2
ELSE
    customercode = 'QD'
END
AND customername like '%渠道%'

13.遍历二维数组

CREATE OR REPLACE FUNCTION "dts_vehicle_resource"."traverse_2_array"("tollgateid_arr" _varchar)
  RETURNS "pg_catalog"."int8" AS $BODY$
	-- 遍历二维数组。
	-- 作者:余伟
	--sql: SELECT * FROM "dts_vehicle_resource"."test"('{{3},{4,5}}')

	DECLARE
	v_sql_seq1 text;
	v_sql_seq2 text;
	result1 record;
	data_num int8;
	tollgateids_temp  varchar;
	
	begin
			raise notice 'tollgateids_temp: %', array_length(tollgateid_arr,1) ;
			raise notice 'tollgateids_temp: %', array_length(tollgateid_arr,2) ;
	 for i in 1 .. array_length(tollgateid_arr,1) loop 
	 	tollgateids_temp:='';
 for k in 1 .. array_length(tollgateid_arr,2) loop
    IF tollgateid_arr[i][k]<>'NULL' THEN
	  tollgateids_temp = tollgateids_temp||''''||tollgateid_arr[i][k]||''',';
		END IF;
		end loop;
			select trim(trailing ',' from tollgateids_temp)||'' into tollgateids_temp;
			raise notice 'tollgateids_temp: %', tollgateids_temp;
		end loop;
RETURN 1; 
end;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100

14.WHERE NOT EXISTS


--场景: 当业务中有一些 包含规则或者剔除规则时候使用。
-- 如果有查询结果,查询结果就会全部被1替代
--当不需要知道结果是什么,只需要知道有没有结果的时候会这样用),可以提高语句的运行效率,
--在大数据量的情况下,提升效果非常明显
SELECT *FROM PUBLIC.book WHERE NOT EXISTS (
SELECT 1 FROM saler WHERE saler."saler_bookId"=book.book_id);
--等价
SELECT *FROM PUBLIC.book WHERE book_id NOT IN (
SELECT saler."saler_bookId" FROM saler )


15. pg中的 like 与 ~*



SELECT *FROM book WHERE book_name LIKE '__语文';
SELECT *FROM book WHERE book_name LIKE '%语文';
SELECT *FROM book WHERE book_name LIKE '%语文%';
SELECT *FROM book WHERE book_name LIKE '高_语_';
SELECT *FROM book WHERE book_name ~* '语文';
SELECT *FROM book WHERE book_name ~* '.*初';

16 .vertica 替代distinct on

使用distinct根据多个字段去重的同时又能选取多个字段值。

法一:SELECT distinct on(book_name,recordtime) * FROM book ;

法二:
SELECT * FROM (
SELECT *,row_number()over(partition by book_name,recordtime ORDER BY book_id)rn
FROM book )a WHERE a.rn=1;

17. 用sum(1)求表行数 

pgsql 使用技巧_第14张图片

 

你可能感兴趣的:(pgsql)