PostgreSQL的儲存過程簡單入門
一、儲存過程結構:
Create or replace function 過程名(引數名 引數型別,…..) returns 返回值型別 as
$body$
//宣告變數
Declare
變數名變數型別;
如:
flag Boolean;
變數賦值方式(變數名型別 :=值;)
如:
str text :=值; / str text; str :=值;
Begin
函式體;
return 變數名; //儲存過程中的返回語句
End;
$body$
Language plpgsql;
二、變數型別 :
除了postgresql內建的變數型別外,常用的還有 RECORD ,表示一條記錄。
整數資料型別:
子型別 |
標準名 |
描述 |
Smalll integer |
Smallint |
一個2位元組的符號型整數,可以儲存-32768到32767的數字 |
Integer |
Int |
一個4位元組的符號型整數,可以儲存-2147483648到2147473647的數字 |
Serial |
和integer一樣,除了它的值通常是由PostgreSQL自動輸入的。 |
浮點資料型別:(浮點資料也可以再細分,分為提供通用功能的浮點值和固定精度的數字)
子型別 |
標準名 |
描述 |
float |
float(n) |
支援最少精度為n,儲存為最多8位元組的浮點數。 |
float8 |
real |
雙精度(8位元組)浮點數字 |
numeric |
numeric(p,s) |
擁有p個數字的實數,其中小數點後有s位。不像float,這始終是一個確切的數字,但工作效率比普通浮點數字低。 |
money |
numeric(9,2) |
PostgreSQL特有的型別,但在其他資料庫裡也普遍存在。Money型別從PostgreSQL 8.0開始不贊成使用,且可能在以後版本中取消。你應該使用number型別代替。 |
注:
儲存float和real型別的資料的行為非常相似,但是numeric列的行為有點不同。Numeric型別不是儲存接近的數,而是在小數後面進行後超出固定長度的部分進行四捨五入。如果我們儲存太大的資料到其中,INSERT將失敗。還要注意float和real也會對數字四捨五入;例如123.456789被四捨五入為123.457。
時間資料型別:
定義 |
意義 |
date |
儲存日期資訊 |
time |
儲存時間資訊 |
timestamp |
儲存日期和時間 |
interval |
儲存timestamp之間差別的資訊 |
timestamptz |
PostgreSQL擴充套件的型別,儲存包含時區資訊的timestamp |
特殊資料型別:
定義 |
意義 |
box |
矩形盒子 |
line |
一組點 |
point |
一對幾何學的數字 |
lseg |
一條線段 |
polygon |
一條封閉的幾何線 |
cidr或inet |
一個IPv4的地址,錄入192.168.0.1 |
macaddr |
以MAC地址(乙太網卡實體地址) |
注:PostgreSQL也允許你使用SQL命令CREATE TYPE在資料庫中建立你自己的型別。這通常不需要,而且在一定程度上,它是PostgreSQL獨有的。
陣列
通常,一個數組需要通過使用一個附加表實現。但是,陣列的能力有時候很有用。建立陣列的方法有兩種:傳統的PostgreSQL的方法和SQL99標準的方法。
PostgreSQL樣式的陣列
要將一個表的列定義為陣列,你可以簡單地在型別後面新增[];不需要定義元素的個數。即使定義了個數,也不會強制要求儲存的個數。
Eg:
test=> CREATE TABLE empworkday (
test(> refcode char(5),
test(> workdays int[]
test(> );
往陣列列中插入值:
test=> INSERT INTO empworkday VALUES(‘val01′,‘{0,1,0,1,1,1,1}’);
test=> INSERT INTO empworkday VALUES(‘val02′,‘{0,1,1,1,1,0,1}’);
SQL99樣式的數字
在SQL99標準中,必須指出元素的個數。
Eg:
test=> CREATE TABLE empworkday (
test(> refcode char(5),
test(> workdays int array[7]
test(> );
test=> INSERT INTO empworkday VALUES(‘val01′,‘{0,1,0,1,1,1,1}’);
test=> INSERT INTO empworkday VALUES(‘val02′,‘{0,1,1,1,1,0,1}’);
三、連線字元:
Postgresql儲存過程中的連線字元不再是“+”,而是使用“||”。
四、 控制結構:
1、if 條件(五種形式)
IF ... THEN
IF ... THEN ... ELSE
IF ... THEN ... ELSE IF
IF ... THEN ... ELSIF ... THEN ... ELSE
IF ... THEN ... ELSEIF ... THEN ... ELSE(注:ELSEIF 是ELSIF 的別名)
2、迴圈
使用LOOP,EXIT,CONTINUE,WHILE, 和FOR 語句,可以控制PL/pgSQL 函式重複一系列命令。
1)、LOOP
[ <<label>> ]
LOOP
statements
END LOOP [ label ];
LOOP 定義一個無條件的迴圈,無限迴圈, 直到由EXIT或者RETURN語句終止。可選的label 可以由EXIT 和CONTINUE 語句使用, 用於在巢狀迴圈中宣告應該應用於哪一層迴圈。
2)、EXIT
EXIT [ label ] [ WHEN expression ];
如果沒有給出label, 那麼退出最內層的迴圈,然後執行跟在 END LOOP 後面的語句。 如果給出 label, 那麼它必須是當前或者更高層的巢狀迴圈塊或者語句塊的標籤。然後該命名塊或者迴圈就會終止,而控制落到對應迴圈/塊的 END 語句後面的語句上。
如果聲明瞭WHEN,迴圈退出只有在expression 為真的時候才發生, 否則控制會落到EXIT 後面的語句上。
EXIT 可以用於在所有的迴圈型別中,它並不僅僅限制於在無條件迴圈中使用。在和 BEGIN 塊一起使用的時候,EXIT 把控制交給塊結束後的下一個語句。
例如:
Loop 迴圈
If … then 條件判斷
Exit ; 條件成立,則退出迴圈。
End if;
End loop;
3)、CONTINUE
CONTINUE [label ] [ WHENexpression ];
如果沒有給出 label,那麼就開始最內層的迴圈的下一次執行。也就是說,控制傳遞迴給迴圈控制表示式(如果有),然後重新計算迴圈體。 如果出現了label,它宣告即將繼續執行的迴圈的標籤。
如果聲明瞭 WHEN,那麼迴圈的下一次執行只有在expression 為真的情況下才進行。否則,控制傳遞給CONTINUE 後面的語句。
CONTINUE 可以用於所有型別的迴圈; 它並不僅僅限於無條件迴圈。
例如:
LOOP
一些計算
EXIT WHEN count > 100;
CONTINUE WHEN count < 50;
一些在count 數值在 [50 .. 100] 裡面時候的計算
END LOOP;
4)、WHILE
[ <<label>> ]
WHILE expression LOOP
statements
END LOOP [ label ];
只要條件表示式為真,WHILE語句就會不停在一系列語句上進行迴圈. 條件是在每次進入迴圈體的時候檢查的.
例如:
WHILE amount_owed > 0 AND gift_certificate_balance > 0 LOOP
-- 可以在這裡做些計算
END LOOP;
WHILE NOT BOOLEAN_expression LOOP
-- 可以在這裡做些計算
END LOOP;
5)、FOR(整數變種)
[ <<label>> ]
FOR name IN [ REVERSE ] expression .. expression LOOP
statements
END LOOP [ labal ];
這種形式的FOR對一定範圍的整數數值進行迭代的迴圈。變數name 會自動定義為integer型別並且只在迴圈裡存在。給出範圍上下界的兩個表示式在進入迴圈的時候計算一次。 迭代步進值總是為 1,但如果聲明瞭REVERSE就是 -1。
一些整數FOR迴圈的例子∶
FOR i IN 1..10 LOOP 表示1迴圈到10
這裡可以放一些表示式
RAISE NOTICE 'i IS %', i;
END LOOP;
FOR i IN REVERSE 10..1 LOOP
這裡可以放一些表示式
END LOOP;
如果下界大於上界(或者是在 REVERSE 情況下是小於),那麼迴圈體將完全不被執行。而且不會丟擲任何錯誤。
3、異常捕獲
EXCEPTION
WHEN 錯誤碼(如:STRING_DATA_RIGHT_TRUNCATION:字串資料右邊被截斷) THEN
/**後臺列印錯誤資訊*/
RAISE NOTICE '錯吳資訊';
五、示例程式碼:
/**
批量插入一批資料,經緯度欄位值要滿足中國地理位置上的經緯度範圍;
注:時間不能指定為同一時間,否則會掃描全表,導致效能低下。下列指令碼未考慮時間的分段,採用的一個時間點。
*/
create orreplace function intobatch() returns integer as
$body$
declare
skyid integer;
lot float;
lat float;
sex varchar;
level integer;
ctime int :=1325404914;
num integer :=0;
total integer :=0;
begin
lot='73.6666666';
lat='3.8666666';
FOR skyid IN 404499817 ..404953416 loop
if(lot > 135.0416666) then
lot=73.6666666;
end if;
if(lat > 53.5500000) then
lat=3.8666666;
end if;
if(skyid%2 <> 0) then
sex='1';
level=0;
else
sex='2';
level=1;
end if;
INSERT INTO user_last_location(user_id,app_id,lonlat,sex,accurate_level,lonlat_point,create_time)
VALUES(skyid,2934,ST_GeomFromText('POINT('||lot||' '||lat||')',4326),sex,level,POINT(lot,lat),to_timestamp(ctime));
lot=lot+0.1;
lat=lat+0.1;
skyid=skyid+1;
end loop;
return skyid;
end
$body$
languageplpgsql;
SELECT *from intobatch();