1.CASCADE 级联删除,如果表或模式或数据库有序列、分区相关 依赖时,需要修改表或模式或数据库,则使用它
DROP SCHEMA viid_facestatic CASCADE
2.pgsql隐藏字段ctid,一般用于去重
3. pg 表自连接使用场景
3.1 有一张卡口表 求距离A卡口L米的所有卡口ID
-- 查询以卡口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)......
场景:已知字段 商品名,年,月,销售额,求累计的销售额
即已知:
求:
代码:
--
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 使用自连接 实现滑动窗口
已知:
求:如果某人在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对应一个滑动窗口
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:求所有采集设备 所属的社区 的社区名称
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)
查询结果
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中按某一个或其中几个字段去重,只保留第一条
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)求表行数