存储过程语法介绍

最近更新时间:2024-10-17 15:26:50

我的收藏

建立存储语法

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
$$
begin
raise notice 'Hello,tdsql_pg';
end;
$$
LANGUAGE PLPGSQL;
CREATE PROCEDURE
postgres=# 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_pg
CALL
postgres=#

[模式名.]存储过程名介绍

建立存储过程,模式名可以指定,也可以不指定,不指定则存放在当前模式下,如上面例子就没有指定模式名,则就存放在当前模式下,如下所示。
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 where
pg_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
$$
begin
raise notice 'Hello tdsql_pg';
end;
$$
LANGUAGE PLPGSQL;
CREATE FUNCTION

postgres=# CREATE PROCEDURE proc_1() AS
$$
begin
raise notice 'Hello tdsql_pg';
end;
$$
LANGUAGE PLPGSQL;
ERROR: function "proc_1" already exists with same argument types
postgres=#
如果要替换,则提示。
postgres=# CREATE OR REPLACE PROCEDURE proc_1() AS
$$
begin
raise notice 'Hello tdsql_pg';
end;
$$
LANGUAGE PLPGSQL;
ERROR: cannot change routine kind
DETAIL: "proc_1" is a function.
postgres=#

删除存储过程

删除不带参数的存储过程

postgres=# CREATE OR REPLACE PROCEDURE proc_1() AS
$$
begin
raise notice 'Hello tdsql_pg';
end;
$$
LANGUAGE PLPGSQL;
CREATE PROCEDURE

postgres=# drop procedure proc_1 ( );
DROP PROCEDURE
postgres=#

删除带参数的存储过程

postgres=# CREATE OR REPLACE PROCEDURE proc_1(a_int int) AS
$$
begin
raise notice '%',a_int;
end;
$$
LANGUAGE PLPGSQL;
CREATE PROCEDURE

postgres=# drop procedure proc_1 ( a_int int);
DROP PROCEDURE
postgres=#
也可以只指定参数的类型即可。
postgres=# drop procedure proc_1 (int);
DROP PROCEDURE
postgres=#

存储过程修改名称

修改不带参数的存储过程名称

postgres=# CREATE OR REPLACE PROCEDURE proc_1() AS
$$
begin
raise notice 'Hello tdsql_pg';
end;
$$
LANGUAGE PLPGSQL;
CREATE PROCEDURE

postgres=# alter procedure proc_1() rename to proc_1_1;
ALTER PROCEDURE
postgres=#

修改带参数的存储过程名称

postgres=# CREATE OR REPLACE PROCEDURE proc_1(a_int int) AS
$$
begin
raise notice '%',a_int;
end;
$$
LANGUAGE PLPGSQL;
CREATE PROCEDURE

postgres=# 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
$$
begin
raise notice 'Hello tdsql_pg';
end;
$$
LANGUAGE PLPGSQL;
CREATE PROCEDURE
postgres=#

postgres=# alter procedure public.proc_1() set schema myche;
ALTER PROCEDURE
postgres=#

修改带参数的存储过程 schema

postgres=# CREATE OR REPLACE PROCEDURE public.proc_1(a_int int) AS
$$
begin
raise notice '%',a_int;
end;
$$
LANGUAGE PLPGSQL;
CREATE PROCEDURE

postgres=# alter procedure public.proc_1 (int) set schema myche;
ALTER PROCEDURE
postgres=#

修改存储过程所属用户

修改不带参数的存储过程所属用户

postgres=# CREATE OR REPLACE PROCEDURE public.proc_1() AS
$$
begin
raise notice 'Hello tdsql_pg';
end;
$$
LANGUAGE PLPGSQL;
CREATE PROCEDURE

postgres=# alter procedure proc_1() owner to tdsql_pg_01_admin;
ALTER PROCEDURE
postgres=#

修改不带参数的存储过程所属用户

postgres=# CREATE OR REPLACE PROCEDURE proc_1(a_int int) AS
$$
begin
raise notice '%',a_int;
end;
$$
LANGUAGE PLPGSQL;
CREATE PROCEDURE

postgres=# alter procedure proc_1 (int) owner to tdsql_pg_01_admin;
ALTER PROCEDURE
postgres=#

存储过程执行

不带参数

postgres=# create or replace procedure p_no_para() as
$$
begin
raise notice 'no_para procedure';
end;
$$
language plpgsql;
CREATE PROCEDURE
postgres=# call p_no_para();
NOTICE: no_para procedure
CALL
postgres=#

带参数

postgres=# create or replace procedure p_para(a_int integer) as
$$
begin
raise notice 'a_int = %',a_int;
end;
$$
language plpgsql;
CREATE PROCEDURE
postgres=# call p_para(1);
NOTICE: a_int = 1
CALL
postgres=#

动态 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) is
type ascii_into is table of number;
var_c1 ascii_into;
v_sql varchar2(200);
begin
v_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 loop
raise 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;
/