建立存储语法
CREATE [OR REPLACE] PROCEDURE [模式名.]存储过程 ([参数模式 [参数名] 数据类型 [default 默认值] [,…]]) AS[标签][DECLARE--变量定义]BEGIN--注释/*注释*/--语句执行END;[标签]LANGUAGE PLPGSQL;
[OR REPLACE] 更新存储介绍
带 OR REPLACE 的作用,在建立存储过程时若存在则替换,建立存储时不带 OR REPLACE 关键字,则遇到函数已经存系统则会报错,如下所示。
postgres=# select prosrc from pg_proc where proname='proc_1';prosrc--------------------------------+begin +raise notice 'Hello tdsql_pg';+end; +(1 row)postgres=# CREATE OR REPLACE PROCEDURE proc_1() AS$$beginraise notice 'Hello,tdsql_pg';end;$$LANGUAGE PLPGSQL;CREATE PROCEDUREpostgres=# select prosrc from pg_proc where proname='proc_1';prosrc---------------------------------+begin +raise notice 'Hello,tdsql_pg';+end; +(1 row)postgres=#postgres=# call proc_1();NOTICE: Hello,tdsql_pgCALLpostgres=#
[模式名.]存储过程名介绍
建立存储过程,模式名可以指定,也可以不指定,不指定则存放在当前模式下,如上面例子就没有指定模式名,则就存放在当前模式下,如下所示。
postgres=# select * from pg_namespace;nspname | nspowner | nspacl--------------------+----------+-------------------------------------pg_toast | 10 |pg_temp_1 | 10 |pg_toast_temp_1 | 10 |pg_catalog | 10 | {postgres=UC/postgres,=U/postgres}public | 10 | {postgres=UC/postgres,=UC/postgres}information_schema | 10 | {postgres=UC/postgres,=U/postgres}(6 行记录)postgres=# show search_path;search_path----------------"$user",public(1 行记录)postgres=# select pg_namespace.nspname,pg_proc.prosrc from pg_proc,pg_namespace wherepg_proc.pronamespace=pg_namespace.oid and pg_proc.proname='proc_1';nspname | prosrc---------+---------------------------------public | +| begin +| raise notice 'Hello,tdsql_pg';+| end; +|(1 row)
因为 $user 模式不存在,所以存在 public 模式下。
存储过程与函数不能同名
如创建一个与函数同名的存储过程会提示 function xxx already exists with same argument types。
postgres=# CREATE OR REPLACE FUNCTION proc_1() RETURNS void AS$$beginraise notice 'Hello tdsql_pg';end;$$LANGUAGE PLPGSQL;CREATE FUNCTIONpostgres=# CREATE PROCEDURE proc_1() AS$$beginraise notice 'Hello tdsql_pg';end;$$LANGUAGE PLPGSQL;ERROR: function "proc_1" already exists with same argument typespostgres=#
如果要替换,则提示。
postgres=# CREATE OR REPLACE PROCEDURE proc_1() AS$$beginraise notice 'Hello tdsql_pg';end;$$LANGUAGE PLPGSQL;ERROR: cannot change routine kindDETAIL: "proc_1" is a function.postgres=#
删除存储过程
删除不带参数的存储过程
postgres=# CREATE OR REPLACE PROCEDURE proc_1() AS$$beginraise notice 'Hello tdsql_pg';end;$$LANGUAGE PLPGSQL;CREATE PROCEDUREpostgres=# drop procedure proc_1 ( );DROP PROCEDUREpostgres=#
删除带参数的存储过程
postgres=# CREATE OR REPLACE PROCEDURE proc_1(a_int int) AS$$beginraise notice '%',a_int;end;$$LANGUAGE PLPGSQL;CREATE PROCEDUREpostgres=# drop procedure proc_1 ( a_int int);DROP PROCEDUREpostgres=#
也可以只指定参数的类型即可。
postgres=# drop procedure proc_1 (int);DROP PROCEDUREpostgres=#
存储过程修改名称
修改不带参数的存储过程名称
postgres=# CREATE OR REPLACE PROCEDURE proc_1() AS$$beginraise notice 'Hello tdsql_pg';end;$$LANGUAGE PLPGSQL;CREATE PROCEDUREpostgres=# alter procedure proc_1() rename to proc_1_1;ALTER PROCEDUREpostgres=#
修改带参数的存储过程名称
postgres=# CREATE OR REPLACE PROCEDURE proc_1(a_int int) AS$$beginraise notice '%',a_int;end;$$LANGUAGE PLPGSQL;CREATE PROCEDUREpostgres=# alter procedure proc_1 (a_int int) rename to proc_1_1;ALTER PROCEDURE
修改存储过程所属 schema
修改不带参数的存储过程 schema
postgres=# CREATE OR REPLACE PROCEDURE public.proc_1() AS$$beginraise notice 'Hello tdsql_pg';end;$$LANGUAGE PLPGSQL;CREATE PROCEDUREpostgres=#postgres=# alter procedure public.proc_1() set schema myche;ALTER PROCEDUREpostgres=#
修改带参数的存储过程 schema
postgres=# CREATE OR REPLACE PROCEDURE public.proc_1(a_int int) AS$$beginraise notice '%',a_int;end;$$LANGUAGE PLPGSQL;CREATE PROCEDUREpostgres=# alter procedure public.proc_1 (int) set schema myche;ALTER PROCEDUREpostgres=#
修改存储过程所属用户
修改不带参数的存储过程所属用户
postgres=# CREATE OR REPLACE PROCEDURE public.proc_1() AS$$beginraise notice 'Hello tdsql_pg';end;$$LANGUAGE PLPGSQL;CREATE PROCEDUREpostgres=# alter procedure proc_1() owner to tdsql_pg_01_admin;ALTER PROCEDUREpostgres=#
修改不带参数的存储过程所属用户
postgres=# CREATE OR REPLACE PROCEDURE proc_1(a_int int) AS$$beginraise notice '%',a_int;end;$$LANGUAGE PLPGSQL;CREATE PROCEDUREpostgres=# alter procedure proc_1 (int) owner to tdsql_pg_01_admin;ALTER PROCEDUREpostgres=#
存储过程执行
不带参数
postgres=# create or replace procedure p_no_para() as$$beginraise notice 'no_para procedure';end;$$language plpgsql;CREATE PROCEDUREpostgres=# call p_no_para();NOTICE: no_para procedureCALLpostgres=#
带参数
postgres=# create or replace procedure p_para(a_int integer) as$$beginraise notice 'a_int = %',a_int;end;$$language plpgsql;CREATE PROCEDUREpostgres=# call p_para(1);NOTICE: a_int = 1CALLpostgres=#
动态 SQL
动态 SQL 是一种在 PL/SQL 运行时生成和执行 SQL 语句的编程方法,为 PL/SQL 编程提供了很大的灵活性。主要应用于一些静态 SQL 无法支持的操作场景,例如 DDL,又或者是一些需要传入参数的 SQL 语句。
动态 SQL 使用 EXECUTE IMMEDIATE 语句处理大多数动态 SQL 语句。如果动态 SQL 语句是返回多行的 SELECT 语句,将 EXECUTE IMMEDIATE 语句与 BULK COLLECT INTO 子句一起使用。动态 SQL 传入参数使用 USING 子句。
示例:
1、使用 USING 字句给动态 SQL 传入参数
CREATE
TABLE
EMP
(
EMPNO NUMBER
(
4
)
CONSTRAINT
PK_EMP
PRIMARY
KEY
,
ENAME VARCHAR2
(
10
)
,
JOB VARCHAR2
(
9
)
,
MGR NUMBER
(
4
)
,
HIREDATE
DATE
,
SAL NUMBER
(
7
,
2
)
,
COMM NUMBER
(
7
,
2
)
,
DEPTNO NUMBER
(
2
)
)
;
INSERT
INTO
EMP
VALUES
(
7369
,
'SMITH'
,
'CLERK'
,
7902
,
to_date
(
'17-12-1980'
,
'dd-mm-yyyy'
)
,
800
,
NULL
,
20
)
;
INSERT
INTO
EMP
VALUES
(
7499
,
'ALLEN'
,
'SALESMAN'
,
7698
,
to_date
(
'20-2-1981'
,
'dd-mm-yyyy'
)
,
1600
,
300
,
30
)
;
INSERT
INTO
EMP
VALUES
(
7521
,
'WARD'
,
'SALESMAN'
,
7698
,
to_date
(
'22-2-1981'
,
'dd-mm-yyyy'
)
,
1250
,
500
,
30
)
;
INSERT
INTO
EMP
VALUES
(
7566
,
'JONES'
,
'MANAGER'
,
7839
,
to_date
(
'2-4-1981'
,
'dd-mm-yyyy'
)
,
2975
,
NULL
,
20
)
;
create
or
replace
procedure
p_sql
is
v_sql
varchar
(
500
)
;
vret number
;
vin number:
=
1111
;
begin
perform dbms_output
.
serveroutput
(
't'
)
;
v_sql:
=
'select sal from emp where empno=:id'
;
execute
immediate v_sql
into
vret
using
7521
;
perform dbms_output
.
put_line
(
vret
)
;
-- raise notice 'vret=%',vret;
end
;
/
call
p_sql
(
)
;
2、SELECT 返回多条记录时,使用 BULK COLLECT INTO 字句。
create table ascii_t(id int, c1 varchar2(100), c2 char(100), c3 nchar(100), c4 nvarchar2(100), c5 clob, c6 nclob, c7 number, c8 smallint, c9 date, c10 timestamp);insert into ascii_t values(1, 'abc', 'eqw', chr(20)||'da', chr(30)||'==', '而我却', chr(465)||'饿我去的', 465.89, -100, '2021-07-06 10:15:12', to_timestamp('2021-07-06 14:38:48.680297', 'yyyy-mm-dd HH24:mi:ss.ff'));insert into ascii_t values(2, '中国', '大苏打', chr(125)||'ddsaa', chr(120)||'==', 'daewq', chr(879)||'大苏打ew', 1.89, 128,'2020-08-06 10:15:12', to_timestamp('2021-07-06 14:38:48.680297', 'yyyy-mm-dd HH24:mi:ss.ff'));insert into ascii_t values(3, '四届', 'eqw', chr(458)||'打算', chr(654)||'==', '打算而我却', chr(135)||'而我打算eqw', 0.89, 0, '2020-08-06 10:15:12', to_timestamp('2021-07-08 14:38:48', 'yyyy-mm-dd HH24:mi:ss'));insert into ascii_t values(4, 'abc', '而且我给v的', chr(20)||'da', chr(445)||'==', '和梵蒂冈', chr(135)||'aeq4556大', -895.89, 11, '2021-08-06 10:15:12', to_timestamp('2021-08-08 14:38:48', 'yyyy-mm-dd HH24:mi:ss'));insert into ascii_t values(5, 'abewqe', 'eqw', chr(34)||'恶趣味', chr(102)||'==', '日期', chr(798)||'321', -7895.89, 22, '2020-09-06 10:15:12', to_timestamp('2021-07-09 14:38:48', 'yyyy-mm-dd HH24:mi:ss'));insert into ascii_t values(6, '打算', 'dasdas', chr(38)||'大师的人情味', chr(128)||'==', '发', chr(4565)||'', 7851.89, -56, '2020-10-06 10:15:12', to_timestamp('2021-10-08 14:38:48', 'yyyy-mm-dd HH24:mi:ss'));-- 插入空值insert into ascii_t values(7, '', 'dasdas','', chr(128)||'==', '发', chr(4565)||'', '', 127, '', '');insert into ascii_t values(8, '打算', '', chr(38)||'大师的人情味', '' ,'发', '', 7895.89, '', SYSDATE, '');insert into ascii_t values(9, '', 'dasdas', '', '', '', chr(4565)||'', 7895.89, '', '', to_timestamp('2021-10-08 14:38:48', 'yyyy-mm-dd HH24:mi:ss'));create or replace procedure ascii_pro(col varchar) istype ascii_into is table of number;var_c1 ascii_into;v_sql varchar2(200);beginv_sql := 'select ascii('||col||') from ascii_t order by id;';execute immediate v_sql bulk collect into var_c1;/*输出雇员信息*/for v_index in var_c1.first .. var_c1.last loopraise notice '%','ascii:'||var_c1[v_index];end loop;end;/call ascii_pro('c2');
3、动态执行 CREATE TABLE
create
table
emp1
as
select
*
from
emp
;
create
table
dept_tmp
(
deptno number
(
2
)
,
dname varchar2
(
14
)
,
loc varchar2
(
13
)
)
;
create
or
replace
package pkg1
is
procedure
raise_salary
(
v1 number
,
v2 number
)
;
end
;
/
create
or
replace
package body pkg1
is
procedure
raise_salary
(
v1 number
,
v2 number
)
is
begin
update
emp1
set
sal
=
sal
+
v2
where
empno
=
v1
;
end
;
end
;
/
DECLARE
sql_stmt VARCHAR2
(
200
)
;
plsql_block VARCHAR2
(
500
)
;
emp_id NUMBER
(
4
)
:
=
7566
;
salary NUMBER
(
7
,
2
)
;
dept_id NUMBER
(
2
)
:
=
50
;
dept_name VARCHAR2
(
14
)
:
=
'PERSONNEL'
;
location VARCHAR2
(
13
)
:
=
'DALLAS'
;
emp_rec emp
%
ROWTYPE
;
BEGIN
EXECUTE
IMMEDIATE
'CREATE TABLE using_t (id NUMBER, amt NUMBER)'
;
sql_stmt :
=
'INSERT INTO dept_tmp VALUES (:1, :2, :3)'
;
EXECUTE
IMMEDIATE sql_stmt
USING
dept_id
,
dept_name
,
location
;
sql_stmt :
=
'SELECT * FROM emp WHERE empno = :id'
;
EXECUTE
IMMEDIATE sql_stmt
INTO
emp_rec
USING
emp_id
;
-- plsql_block := 'BEGIN pkg1.raise_salary(:id, :amt); END;';
plsql_block:
=
'call pkg1.raise_salary(:id, :amt)'
;
EXECUTE
IMMEDIATE plsql_block
USING
7788
,
500
;
-- execute immediate v_sql using in vin, in vret;
-- sql_stmt := 'UPDATE emp SET sal = 2000 WHERE empno = :1
-- RETURNING sal INTO :2';
-- EXECUTE IMMEDIATE sql_stmt USING emp_id RETURNING INTO salary;
EXECUTE
IMMEDIATE
'DELETE FROM dept_tmp WHERE deptno = :num'
USING
dept_id
;
EXECUTE
IMMEDIATE
'ALTER table dept_tmp add c1 number'
;
END
;
/