postgresql 高级用法

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: postgresql 高级用法

1:多态sql

SQL函数可以声明为接受多态类型(anyelement 和 anyarray )的参数或返回多态类型的返回值。

CREATE OR REPLACE FUNCTION get_array(anyelement, anyelement)      ---定义函数
RETURNS anyarray
AS $$
  SELECT ARRAY[$1, $2];
$$ LANGUAGE SQL;
SELECT get_array(1,2) a1, get_array('a'::text,'b'::text) b1;    ---调用函数
     a1    |   b1
-----------+-----------
 {1,2}     | {a,b}
CREATE OR REPLACE FUNCTION is_greater(anyelement, anyelement)
RETURNS BOOLEAN
AS $$
  SELECT $1 > $2;
$$ LANGUAGE SQL;
SELECT is_greater(1.0, 4.5);      f
SELECT is_greater(7.0, 4.5);      t
DROP FUNCTION if exists get_array(anyelement, anyelement);
CREATE OR REPLACE FUNCTION get_array
(IN anyelement, IN anyelement, OUT anyelement, OUT anyarray)
AS $$
  SELECT $1, ARRAY[$1, $2];
$$ LANGUAGE SQL;
SELECT get_array(4,5), get_array('c'::text, 'd'::text);
get_array    |  get_array  
-------------+-------------
 (4,"{4,5}") | (c,"{c,d}")

2: 动态更新sql

--tablename  表名
--feildname  字段名数组
--feildvalue 字段值数组
--returnvalue 返回值
create or replace function f_update
(   tablename         text,
    condition         text,
    feildname         text[],
    feildvalue        text[],
    out returnvalue   text
) as $$
declare
    mysql       text;
    myid        integer;
    myresult    integer;
    items       text;
    counts      integer;
    i           integer;
begin
    counts:=array_length(feildname,1);
    mysql:='update '||quote_ident(tablename)||' set ';
    for i in 1..counts loop
        mysql:= mysql||quote_ident(feildname[i])||'='''||feildvalue[i]||''',';
    end loop;
    mysql:=substring(mysql from 1 for (char_length(mysql)-1)) || ' where 1=1 '||condition;
    execute mysql;
    GET DIAGNOSTICS myresult:= ROW_COUNT; 
    if myresult<>0 then    returnvalue='{"success":"执行更新'||mysql||'成功!"}';
    else                   returnvalue='{"success":"执行更新'||mysql||'失败!"}';
    end if;
end;
$$ language plpgsql;
-- 实际操作
create table test(id integer,name text,gen_time date);
insert into test(id,name,gen_time) values(1,'office','2017-08-19');
select f_update('test',' and id=1','{name,gen_time}','{ssqhan,2017-08-20}');

3:动态更新sql改进

create or replace function f_update_all(
    tablename          text,      
    update_feilds      text,       
    condition_feilds   text,       
    out return_value   text        
) as $$
declare
    ex_sql             text;
    recs               record;
    _key               text ;
    _value             text;
begin
    ex_sql:='update '||quote_ident(tablename)||' set ';
    --setting values for updated table
    for recs in select * from json_array_elements(update_feilds::json)   loop
        _key   := recs.value ->> 'feild_name';
        _value := recs.value ->> 'feild_value' ;
        if json_typeof(recs.value -> 'feild_value') ='number' then 
            ex_sql:=ex_sql|| _key || '=' ||  _value ||',';
        else 
            ex_sql:=ex_sql|| _key || '='''||  (recs.value ->> 'feild_value')  || ''',';
        end if;
    end loop;
    ex_sql:= substring(ex_sql from 0 for length(ex_sql));
    --setting condition in where 
     ex_sql:=ex_sql||' where 1=1';
    for recs in select * from  json_array_elements(condition_feilds::json)  loop
        _key   := recs.value ->> 'feild_name';
        _value := recs.value ->> 'feild_value' ;
         if json_typeof(recs.value -> 'feild_value') ='number' then 
            ex_sql:=ex_sql|| ' and ' || _key || '=' ||  _value ||',';
        else 
            ex_sql:=ex_sql|| ' and ' || _key || '='''||  (recs.value ->> 'feild_value') || ''',';
        end if;
    end loop;
    ex_sql:= substring(ex_sql from 0 for length(ex_sql));
    return_value:=ex_sql;
end;
$$ language plpgsql;

4:动态插入sql

drop function f_insert_all(text,text);
create or replace function f_insert_all(
    table_name         text,       --表名
    insert_feilds      text,       --需要插入的字段和字段 [{"feild_name":"pt_name","feild_value":"我是中国人"},{"feild_name":"pt_description","feild_value":"我骄傲"}]
    out return_value   text        --返回值
) as $$
declare
    ex_sql             text;
    recs               record;
    _key               text ;
    _value               text;
    ex_result           integer;
    _maxid               integer;
begin
    --检查是否插入重复数据,如果重复,返回重复提示
    ex_result:=f_insert_check(table_name,insert_feilds);
    if ex_result<>0 then
        return_value:='{"ERROR":"插入操作失败!请检查是该记录是否已存在!"}';
    else
        _maxid:=f_getnewid(table_name,'id');
        ex_sql:='insert into '||quote_ident(table_name)||'(id';
        _value:='('||_maxid;
        for recs in select * from json_array_elements(insert_feilds::json)   loop
            ex_sql   := ex_sql|| ',' || (recs.value ->> 'feild_name');            --insert feilds
            if json_typeof(recs.value -> 'feild_value') ='number' then 
                _value:=_value||','  ||(recs.value ->> 'feild_value') ;            --insert values numeric
            else 
                _value:=_value||','''||(recs.value ->> 'feild_value')||'''' ;    --insert values not numeric
            end if;
        end loop;
        ex_sql:=ex_sql||') values'||_value||')';
        execute ex_sql; 
        GET DIAGNOSTICS ex_result:= ROW_COUNT; 
        if ex_result<>0 then  return_value:='{"SUCCESS":"插入操作'||ex_sql||'成功!","id":'||_maxid||'}';
        else                  return_value:='{"ERROR":"插入操作'||ex_sql||'失败!"}';
        end if;
        --return_value:='{"ERROR":"插入操作'||ex_result||'失败!"}';
    end if;
end;
$$ language plpgsql;

5:动态行转列

CREATE or REPLACE FUNCTION 
long_to_wide(
table_name VARCHAR,
row_name VARCHAR,
cat VARCHAR,
value_field VARCHAR)
returns void as
$$
/*
table_name : 表名
row_name : 行名字段
cat : 转换为列名的字段
value_field : 转换为值的字段
*/
DECLARE v_sql text;
arow record;
value_type VARCHAR;
BEGIN
    v_sql='
    drop table if exists temp_table;
    CREATE TABLE temp_table as 
    SELECT distinct '||cat||' as col from  '||table_name||'
    order by '||cat;
    execute v_sql;
    v_sql='
    SELECT t.typname AS type
    FROM pg_class c
    ,pg_attribute a
    ,pg_type t  
    WHERE c.relname = lower('''||table_name||''') 
    and a.attnum > 0 
    and a.attrelid = c.oid 
    and a.atttypid = t.oid  
    and a.attname='''||value_field||'''
    ORDER BY a.attnum
    '; 
    execute v_sql into value_type;--获取值字段的数据类型
    v_sql='select '||row_name;
    IF value_type in ('numeric','int8','int4','int')--判断值字段是否是数值型 
        THEN    
        FOR arow in (SELECT col FROM temp_table) loop
        v_sql=v_sql||'
                ,sum(case '||cat||' when '''||arow.col||''' then '||value_field||' else 0 end) '||cat||'_'||arow.col;
        end loop;
    ELSE 
        FOR arow in (SELECT col FROM temp_table) loop
        v_sql=v_sql||'
        ,string_agg((case '||cat||' when '''||arow.col||''' then '||value_field||' else '''' end),'''') '||cat||'_'||arow.col;
        end loop;
    END IF;
    v_sql='
                drop table if exists '||table_name||'_wide;
                CREATE TABLE '||table_name||'_wide as 
                '||v_sql||' 
                from '||table_name||' 
                group by '||row_name||';
                drop table if exists temp_tabl
                ';
    execute v_sql;
end;
$$ LANGUAGE plpgsql;
SELECT long_to_wide('Student_grade', '姓名','课程', '等级')   ---调用函数  生成的表名为Student_grade_wide

6:静态行转列

CREATE EXTENSION tablefunc;
select * from crosstab('select s_name::text, s_class, c_value from test1 order by 1,2')
as ct (姓名 text,"化学" numeric,"数学" numeric,"物理" numeric,"英语" numeric,"语文" numeric

7:generate_series函数

SELECT * FROM generate_series('2008-03-01 00:00'::timestamp,
                              '2020-03-04 12:00', '1 month')                
SELECT * FROM generate_series('2008-03-01 00:00'::timestamp,
                              '2020-03-04 12:00', '10 hours');                
SELECT current_date + s.a AS dates FROM generate_series(0,14,1) AS s(a);
SELECT current_date - s.a AS dates FROM generate_series(0,14,1) AS s(a);
SELECT to_char(generate_series('2008-03-01'::date,'2008-03-04', '1 days'),'yyyy-MM-dd'); 

8:json函数

select * from json_each('{"a":"foo", "b":"bar"}')  ;
select * from json_each_text('{"a":"foo", "b":"bar"}')  ;
select * from json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}','f2');
select * from jsonb_pretty('[{"f1":1,"f2":null},2,null,3]');
select * from jsonb_set('[{"f1":1,"f2":null},2]', '{0,f3}','[2,3,4]');
select * from json_array_elements_text('["foo", "bar"]');
select * from json_array_elements('[1,true, [2,false]]');
select * from json_object_keys('{"f1":"abc","f2":{"f3":"a", "f4":"b"}}');
    相关实践学习
    使用PolarDB和ECS搭建门户网站
    本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
    阿里云数据库产品家族及特性
    阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
    相关文章
    |
    SQL 关系型数据库 PostgreSQL
    PostgreSQL datediff 日期间隔(单位转换)兼容SQL用法
    标签 PostgreSQL , datediff 背景 使用datediff,对时间或日期相减,得到的间隔,转换为目标单位(日、月、季度、年、小时、秒。。。等)的数值。 DATEDIFF ( datepart, {date|timestamp}, {date|timestamp} ) 周...
    14298 0
    |
    SQL 存储 移动开发
    PostgreSQL psql的使用,SQL语法,数据类型,递归SQL用法(四)|学习笔记
    快速学习3 PostgreSQL psql的使用,SQL语法,数据类型,递归SQL用法(四)
    382 0
     PostgreSQL psql的使用,SQL语法,数据类型,递归SQL用法(四)|学习笔记
    |
    SQL 关系型数据库 数据库
    3 PostgreSQL psql的使用,SQL语法,数据类型,递归SQL用法(三)|学习笔记
    快速学习3 PostgreSQL psql的使用,SQL语法,数据类型,递归SQL用法(三)
    304 0
    |
    SQL 关系型数据库 PostgreSQL
    PostgreSQL 数据rotate用法介绍
    标签 PostgreSQL , 按时间覆盖历史数据 背景 在某些业务场景中,数据有冷热之分,例如业务只关心最近一天、一周或者一个月的数据。对于历史的数据可以丢弃。 比如某些指标的监控场景,保留一周的监控数据,历史的都可以丢弃。
    3156 0
    |
    SQL XML 移动开发
    【学习资料】第14期快速入门PostgreSQL应用开发与管理 - 4 高级SQL用法
    大家好,这里是快速入门PostgreSQL应用开发与管理 - 4 高级SQL用法
    |
    关系型数据库 数据库 PostgreSQL
    Postgresql pg_dump&pg_restore用法
    PostgreSQL提供的一个工具pg_dump,逻辑导出数据,生成sql文件或其他格式文件,pg_dump是一个客户端工具,可以远程或本地导出逻辑数据,恢复数据至导出时间点。pg_dump 一次只转储一个数据库, 并且不会转储有关角色或表空间的信息 (因为那些是群集范围而不是每个数据库)。
    11225 0
    |
    SQL 关系型数据库 PostgreSQL
    PostgreSQL>窗口函数的用法
    PostgreSQL之窗口函数的用法   转载请注明出处:https://www.cnblogs.com/funnyzpc/p/9311281.html     PostgreSQL的高级特性本准备三篇的(递归、窗口函数、JSON),结果中间一直一直加班 和遗忘 拖到现在才写到中篇,欸,加班真不是一件好事情。
    1652 0