PGSQL存儲過程學習


一、存儲過程定義:

        存儲過程(Stored Procedure)是在大型數據庫系統中,一組為了完成特定功能的SQL 語句集,它存儲在數據庫中,一次編譯后永久有效,用戶通過指定存儲過程的名字並給出參數(如果該存儲過程帶有參數)來執行它。存儲過程是數據庫中的一個重要對象。在數據量特別龐大的情況下利用存儲過程能達到倍速的效率提升

 

二、存儲過程的結構

  案例: 創建一個求長方形面積的存儲過程。

create or replace function area_of_rectangle(lenth integer,height integer)  --存儲過程名稱與參數【參數格式:(變量名1 變量類型 , 變量名2 變量類型,…)
returns integer as  --有“s”
$$
declare                      --declare表示聲明變量,可以聲明多個變量
	area integer := 0;   --定義面積變量數據類型
begin
	area := lenth * height;   --主邏輯與返回值
	return area;              --返回值
end $$ language 'plpgsql'; 

注意:兩個
$$ 符中間可以填入符合命名規則的任意字符,如$body$、$aaaa$。但是下方的美元符必須與這里的保持一致。

 

 

 

調用存儲過程:

 

 

 

二、變量使用

1.變量類型:存儲過程中,對變量賦值需要兩個值類型一致;

 

 

 注意:record類型變量是“記錄類型”的變量,用於存儲多行多列的值。
  按官方文檔的說明,record類型的變量並不是真正的變量,該類型變量在第一次賦值前,它有多少列、每一列是什么類型都是不確定的。在第一次賦值后,該變量就根據值自動確定列的數量和各列的類型。



三、賦值

  3.1、靜態賦值:

           student_name := '張靜';

 

  3.2、動態賦值:

    select name into student_name from class where stu_No = 1;
    --或者
    execute 'select name from class where stu_No = 1' into student_name;

四、基本流程語句:存儲過程中,使用RAISE NOTICE可以在運行時將變量輸出顯示

4.1、if語句

IF ... THEN ... END IF;
IF ... THEN ... ELSE ... END IF;
IF ... THEN ... ELSE ... THEN ... ELSE ... END IF;
--例:
if student_name = '張靜' then
    RAISE NOTICE '我是張靜';
else if student_name like '%李%' then
    RAISE NOTICE '我姓李';
else
    RAISE NOTICE '我不是張靜,也不姓李';

 

4.2、case語句

CASE ... WHEN ... THEN ... ELSE ... END CASE;
CASE WHEN ... THEN ... ELSE ... END CASE;
--例:
case student_name when '張靜','曉靜' then
    RAISE NOTICE '張靜和曉靜都是我的名稱';
else 
    RAISE NOTICE '你叫錯名字了';
end case;
--例: case when student_name = '張靜' or student_name = '曉靜' then RAISE NOTICE '張靜和曉靜都是我的名稱'; else RAISE NOTICE '你叫錯名字了'; end case;

 

4.3、循環  

[ <<label>> ]
LOOP
    循環體語句;
    EXIT [ label ] [ WHEN 判斷條件表達式 ];
END LOOP [ label ];

--例-計算1到100的和:
sum := 0; i := 0; loop i := i + 1; sum := sum + i; exit when i = 100 ; end loop; RAISE NOTOCE '1到100的和為:%',sum;

[ <<label>> ]
WHILE 判斷條件表達式 LOOP
    循環體語句;
END LOOP [ label ];

--例 - 計算1到100的和:
sum := 0;
i := 1;
while i<=100 loop
    sum := sum + i;
    i := i + 1;
end loop
RAISE NOTOCE '1到100的和為:%',sum;
[ <<label>> ]
FOR 循環控制變量 IN [ REVERSE ] 循環范圍 [ BY expression ] LOOP
    循環體語句;
END LOOP [ label ];

--計算1到100的和:
--例1 - 循環執行過程類似於:for(i=1;i<=100;i++){}
sum := 0;
for i in 1..100 loop
    sum := sum + i;
end loop;
RAISE NOTOCE '1到100的和為:%',sum;

--例2 - 循環執行過程類似於:for(i=100;i>=1;i--){}
sum := 0;
for i in REVERSE 100..1 loop
    sum := sum + i;
end loop;
RAISE NOTOCE '1到100的和為:%',sum;

--計算1到100之間所有奇數的和
--例3 - 循環執行過程類似於:for(i=1;i<=100;i=i+2){}
sum := 0;
for i in 1..100 by 2 loop
    sum := sum + i;
end loop;
RAISE NOTOCE '1到100的和為:%',sum;
[ <<label>> ]
FOR 變量 IN 查詢語句 LOOP
    循環體語句;
END LOOP [ label ];

--例 - 遍歷班級中每個人的名字:
for student_name in select name from class loop
    RAISE NOTICE '姓名:%',student_name;
end loop;

四、查詢並返回多條記錄

案例1:

create or replace function f_get_member_info(id integer)
returns setof record as --setof是關鍵字,暫時不清楚其作用;record是返回的數據類型,即記錄類型數據;
$$                      --兩個美元符必須存在,中間可以填入符合命名規則的字符(如$body$,$abc$),但必須與下方的兩個美元符相統一
declare
    rec record;         --定義記錄類型的變量,用於存儲查詢的結果
begin
    --開始for循環,執行SELECT語句。注意,loop后沒有分號!
    for rec in EXECUTE 'SELECT id,real_name FROM a_account_all' loop
        return next rec;          --將查詢結果依次追加到rec變量中
    end loop;                     --for循環結return;
end
$$
language 'plpgsql';

--調用存儲過程f_get_member_info示例 -- a_account_all 為存儲過程中被查詢的表,id和real_name是表中的字段,也是在存儲過程中被查詢的字段
SELECT * FROM f_get_member_info(1568) as a_account_all(id integer,real_name character varying(50));

 

CREATE OR REPLACE FUNCTION public.test()
    RETURNS SETOF record 
    LANGUAGE 'plpgsql'
    
    --這三句話我也還沒搞懂其含義,但加上不會報錯
    COST 100
    VOLATILE 
    ROWS 1000
    
AS $BODY$
DECLARE
    temp_rec record ;--第一個記錄集
    rec record ;--第二個記錄集
BEGIN
    --給第一個結果集賦值
    for temp_rec in execute 'SELECT 1,2,3' loop
        return next temp_rec;
        RAISE NOTICE 'temp_rec:%',temp_rec;
    end loop;
    
    --給第二個結果集賦值
    for rec in execute 'SELECT 4,5,6' loop
        return next rec;
        RAISE NOTICE 'rec:%',rec;
    end loop;
    
    --給第二個結果集追加值
    rec := (9,8,7);
    return next rec;

    --將兩個結果集一起返回
    return ;
END
$BODY$;

ALTER FUNCTION public.test()
    OWNER TO postgres;

-- 調用示例:
SELECT * FROM test() as temp1(num_1 integer,num_2 integer,num_3 integer);

 

 

 

實戰案例:獲取數據表中ID最大值:

CREATE  TABLE department(
   ID INT PRIMARY KEY                         NOT NULL,
   d_code                                     VARCHAR(50),
   d_name                                     VARCHAR(50)     NOT NULL,
   d_parentID                                 INT             NOT NULL  DEFAULT 0
); 

insert into department values(1,'001','office');
insert into department values(2,'002','office',1);

 

 

 

create or replace function f_getNewID(myTableName text,myFeildName text) returns integer as $$
declare
    mysql text;
    myID integer;
begin
    mysql:='select max('
        || quote_ident(myFeildName) 
        ||') from '
        || quote_ident(myTableName);
    execute mysql into myID; 
    --using myTableName,myFeildName;
    
    if myID is null or myID=0 then return 1;
    else return myID+1;
      end if;
end;
$$ language plpgsql;



調用:
select f_getnewid('department','id');
 

 

 

總結一下:

1、存儲過程(FUNCITON)變量可以直接用  || 拼接。上面沒有列出,下面給個栗子;

create or replace function f_getNewID(myTableName text,myFeildName text) returns integer as $$ declare mysql text; myID integer; begin mysql:='select max('|| $2 || ' ) from '||$1; execute mysql into myID using myFeildName,myTableName; if myID is null or myID=0 then return 1; else return myID+1; end if; end; $$ language plpgsql;

2、存儲過程的對象不可以直接用變量,要用 quote_ident(objVar)

3、$1  $2是 FUNCTION 參數的順序,如1中的 $1 $2交換,USING 后面的不換 結果 :select max(myTableName) from myFeildname

4、注意:SQL語句中的大寫全部會變成小寫,要想大寫存大,必須要用雙引號。

 

總結:

1. 運行速度:對於很簡單的 sql ,存儲過程沒有什么優勢。對於復雜的業務邏輯,因為在存儲過程創建的時候,數據庫已經對其進行了一次解析和優化。存儲過程一旦執行,在內存中就會保留一份這個存儲過程,這樣下次再執行同樣的存儲過程時,可以從內存中直接調用,所以執行速度會比普通 s ql 快。

2. 減少網絡傳輸:存儲過程直接就在數據庫服務器上跑,所有的數據訪問都在數據庫服務器內部進行,不需要傳輸數據到其它服務器,所以會減少一定的網絡傳輸。但是在存儲過程中沒有多次數據交互,那么實際上網絡傳輸量和直接 sql 是一樣的。而且我們的應用服務器通常與數據庫是在同一內網,大數據的訪問的瓶頸會是硬盤的速度,而不是網速。

3. 可 維護性:的存儲過程有些時候比程序更容易維護,這是因為可以實時更新 DB 端的存儲過程 。 有些 bug ,直接改存儲過程里的業務邏輯,就搞定了。

4. 增強安全性:提高代碼安全,防止 SQL 注入 。這一點 sql 語句也可以做到。

 

5. 可擴展性:應用程序和數據庫操作分開,獨立進行,而不是相互在一起。方便以后的擴展和 DBA 維護優化。

 

 

 

 

這里轉載於:https://blog.csdn.net/anju2054/article/details/102235578?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-2.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-2.control

 

https://blog.csdn.net/Mr_Door/article/details/102527225

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM