1. 程式人生 > >PostgreSQL的儲存過程簡單入門

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型別代替。

注:

儲存floatreal型別的資料的行為非常相似,但是numeric列的行為有點不同。Numeric型別不是儲存接近的數,而是在小數後面進行後超出固定長度的部分進行四捨五入。如果我們儲存太大的資料到其中,INSERT將失敗。還要注意floatreal也會對數字四捨五入;例如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();