https://www.flickr.com/photos/8058098@N07/2718571627/
在預存程序中,可透過「SELECT」語句,得到想要的查詢結果。但如果我們想要的不是查看結果,而是像一般程式語言的陣列那樣,能夠逐一取出裡面的資料作處理,此時就需要用到「游標」(cursor)了。
本文會介紹游標的使用方式,並搭配「處理器」(handler)進行錯誤處理。
一、測試資料
以下是本文使用的測試資料。
員工表,包含員工編號與名字,共兩個欄位。
銷售紀錄表,包含員工編號、銷售日期與金額,共三個欄位。
根據以上的測試資料,以下的查詢語法,是統計 2023 年每位員工的銷售金額。
結果為:
emp_id | sum_sales |
---|---|
206 | 91000 |
207 | 121940 |
208 | 62800 |
讀者可以將查詢結果想像成「陣列」。在預存程序中,當我們想從查詢結果,逐一處理每一筆資料(就像處理陣列中的每一個元素),就需要用到「游標」(cursor)了。
二、游標(cursor)
以下的預存程序,是將上述查詢指定年度總銷售額的結果,儲存到叫做「employee_yearly_sales_snapshot」的獨立資料表中。
在上面的程式中,宣告了一個叫做「cursor_sales」的游標。語法為 DECLARE 名稱 CURSOR FOR 查詢語法;。
游標有三個操作方式。
- OPEN:開啟游標,將查詢結果放進快取。
- FETCH INTO:取出下一筆資料的各個欄位值。
- CLOSE:關閉游標,從快取清除資料。
Cursor 宛如一個「指針」,會在記憶體中移動到下一筆資料的位置,我們並無法從中得知總共有幾筆資料。於是在範例程式中,筆者暫時寫出 WHILE true DO 這樣的無窮迴圈,來不斷取出資料。到了第三節,我們再來做調整。
使用 FETCH 能從 cursor 取出下一筆資料,並透過 INTO,將欄位值賦予給各個變數。要注意的是,變數名稱的順序,在撰寫上必須與查詢結果的欄位相同。
三、錯誤處理
若讀者執行上面完成的預存程序,會發現資料確實有插入到新的資料表中。然而出現了以下的錯誤訊息:
Error Code: 1329. No data - zero rows fetched, selected, or processed
會出現此訊息,是因為 cursor 的 FETCH 操作已經走訪完所有資料,已經找不到下一筆了。讀者可在官方文件中搜尋「1329」這個錯誤碼(Error Code),會找到「02000」的狀態碼(SQLSTATE)。
為了因應這項錯誤,本節將介紹「處理器」(handler)來進行錯誤處理。處理器的宣告語法如下:
DECLARE 動作 HANDLER FOR 狀態 BEGIN 處理流程 END;
宣告時有三個需要自定義的地方。
- 動作(action):可選擇「EXIT」或「CONTINUE」。前者代表要停止執行當前的程式,後者則繼續執行。
- 狀態(state):可提供的參數包含明確的狀態碼(如上述的 02000)、「SQLWARNING」(所有 01 開頭的狀態碼)、「NOT FOUND」(所有 02 開頭的狀態碼),以及「SQLEXCEPTION」(其他錯誤)。
- 處理流程:發生錯誤時要執行的程式。
那麼,讓我們透過處理器來調整上一節的預存程序。以下會省略部份程式碼,讓讀者專注於使用方式。
此處用來取出 cursor 資料的迴圈,是透過名為「is_cursor_sales_done」的變數,來控制是否要循環。若試圖取出資料時發生「02000」狀態的錯誤,則處理器將該變數值設為 1,藉此離開迴圈。隨後繼續執行後面的程式碼。
在宣告處理器時,除了直接定義要處理的狀態碼,亦能考慮使用 `NOT FOUND` 關鍵字來囊括多個狀態碼,也能增加可讀性。
下一篇:...
留言
張貼留言