postgresql 使用游標筆記


  游標介紹:游標是一種從表中檢索數據並進行操作的靈活手段,游標主要用在服務器上,處理由客戶端發送給服務端的sql語句,或是批處理、存儲過程、觸發器中的數據處理請求。

       游標的優點在於它允許應用程序對查詢語句select 返回的行結果集中每一行進行相同或不同的操作,而不是一次對整個結果集進行同一種操作;它還提供對基於游標位置而對表中數據進行刪除或更新的能力。缺點是處理大數據量時,效率低下,占用內存大。一般來說,能使用其他方式處理數據時,最好不要使用游標,除非是當你使用while循環,子查詢,臨時表,表變量,自建函數或其他方式都無法處理某種操作的時候,再考慮使用游標。

        游標是系統為用戶開設的一個數據緩沖區,存放SQL語句的執行結果。游標的一個常見用途就是保存查詢結果,以便以后使用。游標的結果集是由SELECT語句產生,如果處理過程需要重復使用一個記錄集,那么創建一次游標而重復使用若干次,比重復查詢數據庫要快的多。

        PostgreSQL游標可以封裝查詢並對其中每一行記錄進行單獨處理。當我們想對大量結果集進行分批處理時可以使用游標,因為一次性處理可能造成內存溢出。另外我們可以定義函數返回游標類型變量,這是函數返回大數據集的有效方式,函數調用者根據返回游標對結果進行處理。

  游標使用順序:聲明游標   >   打開游標   >  使用游標   >   關閉游標 。 

 

  先展示一個游標的示例,以下get_film_titles(integer)函數接受代表電影發行年份的參數。在函數內部,我們查詢所有發行年份等於傳遞給該函數的發行年份的電影。我們使用光標在各行之間循環,並連接標題和標題包含ful 單詞的電影發行年份。

CREATE OR REPLACE FUNCTION get_film_titles(p_year INTEGER)
   RETURNS text AS $$
-- 聲明游標
DECLARE 
 titles TEXT DEFAULT '';
 rec_film   RECORD;
 cur_films CURSOR(p_year INTEGER) FOR SELECT * FROM film WHERE release_year = p_year;
BEGIN
   -- 打開游標
   OPEN cur_films(p_year);
 
   LOOP
    -- 獲取記錄放入film
      FETCH cur_films INTO rec_film;
    -- exit when no more row to fetch
      EXIT WHEN NOT FOUND;
 
    -- 構建輸出
      IF rec_film.title LIKE '%ful%' THEN 
         titles := titles || ',' || rec_film.title || ':' || rec_film.release_year;
      END IF;
   END LOOP;
  
   -- 關閉游標
   CLOSE cur_films;
 
   RETURN titles;
END; $$
 
LANGUAGE plpgsql;

SELECT get_film_titles(2006);

--返回結果 ,Grosse Wonderful:2006,Day Unfaithful:2006,Reap Unfaithful:2006,Unfaithful Kill:2006,Wonderful Drop:2006

 

 

一、聲明游標

  PostgreSQL聲明游標有兩種方法,一種是使用特殊類型REFCURSOR聲明游標變量,另一種是聲明和查詢綁定使用。

-- 第一種方式
DECLARE  my_cursor REFCURSOR;

-- 第二種方式
cursor_name [ [NO] SCROLL ] CURSOR [( name datatype, name data type, ...)] FOR query;

  首先,為光標指定一個變量名。接着指定是否可以使用向后滾動光標SCROLL,如果使用NO SCROLL,則光標無法向后滾動。然后,在CURSOR關鍵字后面加上一個逗號分隔的參數列表(name datatype),這些參數定義了查詢的參數。打開游標時,這些參數將被值替換。最后,可以在FOR關鍵字之后指定查詢,使用任何有效的SELECT語句。

  示例:

DECLARE
    cur_films  CURSOR FOR SELECT * FROM film;
    cur_films2 CURSOR (year integer) FOR SELECT * FROM film WHERE release_year = year;

-- 該cur_films 包含film表所有行。
-- 本cur_films2 包含film表特定發行年份的記錄。

 

 

二、打開游標

   PostgreSQL提供了用於打開未綁定和綁定的游標的語法。

  1.打開未綁定的游標

OPEN unbound_cursor_variable [ [ NO ] SCROLL ] FOR query;
-- 由於聲明時未綁定的游標變量未綁定到任何查詢,因此在打開它時必須指定查詢。請參見以下示例:
OPEN my_cursor FOR SELECT * FROM city WHERE counter = p_country;

-- PostgreSQL允許我們打開游標並將其綁定到動態查詢。語法如下:
OPEN unbound_cursor_variable[ [ NO ] SCROLL ]
FOR EXECUTE query_string [USING expression [, ... ] ];

-- 在下面的示例中,我們構建一個動態查詢,該動態查詢根據一個sort_field參數對行進行排序,並打開執行該動態查詢的游標。
query := 'SELECT * FROM city ORDER BY $1';
OPEN cur_city FOR EXECUTE query USING sort_field;

 

  2.打開綁定的游標

 因為綁定游標在聲明時已經綁定到查詢,所以當我們打開它時,只需要在必要時將參數傳遞給查詢。
OPEN cursor_variable[ (name:=value,name:=value,...)];
-- 在下面的示例中,我們打開了綁定游標,cur_films並cur_films2在上面聲明了該游標:
OPEN cur_films;
OPEN cur_films2(year:=2005);

 

 

三、使用游標

  使用FETCH,MOVE,UPDATE或DELETE語句操作游標。

   1.獲取下一行

FETCH [ direction { FROM | IN } ] cursor_variable INTO target_variable;
該FETCH語句從游標中獲取下一行,並為其分配一個target_variable,它可以是記錄,行變量或逗號分隔的變量列表。如果找不到更多行,則將target_variable其設置為NULL(s)。

  如果不顯示指定方向,方向缺省為NEXT。可以有下面值:

  • NEXT
  • LAST
  • PRIOR
  • FIRST
  • ABSOLUTE count
  • RELATIVE count
  • FORWARD
  • BACKWARD

  請注意,FORWARD和BACKWARD方向僅適用於用SCROLL option 聲明的游標。

  示例:

FETCH cur_films INTO row_film;
FETCH LAST FROM row_film INTO title, release_year;

 

  2.移動光標

MOVE [ direction { FROM | IN } ] cursor_variable;

  如果只想移動游標而不檢索任何行,則使用該MOVE語句。方向接受與FETCH語句相同的值。

MOVE cur_films2;
MOVE LAST FROM cur_films;
MOVE RELATIVE -1 FROM cur_films;
MOVE FORWARD 3 FROM cur_films;

 

  3.刪除和更新行

  使用DELETE WHERE CURRENT OF或UPDATE WHERE CURRENT OF語句刪除或更新游標標識的行。

UPDATE table_name
SET column = value, ...
WHERE CURRENT OF cursor_variable;
 
DELETE FROM table_name
WHERE CURRENT OF cursor_variable;

示例:
UPDATE film SET release_year = p_year WHERE CURRENT OF cur_films;

 

 

四、關閉游標

 使用CLOSE關閉打開的游標,CLOSE語句釋放資源或釋放游標變量,以允許使用該OPEN語句再次打開它。

CLOSE cursor_variable;

 

 

五、其他

-- 臨時表返回結果例子
BEGIN;
DO $$
    DECLARE
        temp_geometry st_geometry;  
        geometry_record RECORD;
        cur_geometry CURSOR FOR SELECT shape as shape FROM mainbasin;
    BEGIN
        OPEN cur_geometry;
        FETCH cur_geometry INTO temp_geometry;
        LOOP
            FETCH cur_geometry INTO geometry_record;
            EXIT WHEN NOT FOUND;
            temp_geometry := st_union(temp_geometry,geometry_record.shape);
        END LOOP;
        CLOSE cur_geometry;

        DROP TABLE IF EXISTS temp_table;
        CREATE TEMP TABLE temp_table AS 
        SELECT st_envelope(temp_geometry) shape;
    END; 
$$;
COMMIT;
SELECT st_astext(shape) FROM temp_table;


 

 

參考:https://www.postgresqltutorial.com/plpgsql-cursor/


免責聲明!

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



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