Using Stored Programs with MySQLdb

来源:http://www.cnblogs.com/kungfupanda/archive/2016/09/14/5870460.html
-Advertisement-
Play Games

http://flylib.com/books/en/1.142.1.125/1/ Using Stored Programs with MySQLdb The techniques for calling stored programs with MySQLdb differ only sligh ...


http://flylib.com/books/en/1.142.1.125/1/

 

Using Stored Programs with MySQLdb

The techniques for calling stored programs with MySQLdb differ only slightly from those for using traditional SQL statements. That is, we create a cursor, execute the SQL to call the stored program, and iterate through result sets. The two key differences are that we must potentially deal with multiple result sets and that we may have to retrieve output parameters from the stored program call.

If you read the Python DB API specification, you might notice that the specification includes a cursor method for directly calling stored programsthe callproc cursor method. The callproc method was not implemented in MySQLdb as we went to press, although the maintainer of MySQLdb, Andy Dustman, is working on an implementation that will likely be available by the time you read this. Check out the book's web site (see the Preface) for an update. This method is not implemented in MySQLdb (version 1.2, at least). Luckily, everything you need to call stored programs is available through other methods, so you don't need to wait for callproc to use stored programs with Python.

16.3.1. Calling Simple Stored Programs

The procedure for calling a simple stored programone that returns no result sets and takes no parametersis the same as for executing any non-SELECT statement. We create a cursor and execute the SQL text, as shown in Example 16-18.

Example 16-18. Executing a simple stored procedure

 

cursor1=conn.cursor( ) cursor1.execute("call simple_stored_proc( )") cursor1.close( ) 

 

If the stored procedure takes input parameters, we can supply them using the second argument to the execute( ) method. In Example 16-19, we define a Python function that accepts input parameters and applies them to the sp_apply_discount procedure.

Example 16-19. Supplying input parameters to a stored procedure

 

def apply_discount(p1,p2):  cursor1=conn.cursor( ) cursor1.execute("call sp_apply_discount(%s,%s)",(p1,p2)) cursor1.close( ) 

 

16.3.2. Retrieving a Single Stored Program Result Set

Retrieving a single result set from a stored program is exactly the same as retrieving a result set from a SELECT statement. Example 16-20 shows how to retrieve a single result set from a stored procedure.

Example 16-20. Retrieving a single result set from a stored procedure

 

cursor1=conn.cursor(MySQLdb.cursors.DictCursor) cursor1.execute("CALL sp_emps_in_dept(%s)",(1)) for row in cursor1: print "%d %s %s" % \ (row['employee_id'],row['surname'],row['firstname']) cursor1.close( ) 

 

If you receive a 1312 error at this point (PROCEDURE X can't return a result set in the given context), then it is an indication that you need to specify the CLIENT.MULTI_RESULTS flag in your connection, as outlined in "Creating a Connection" earlier in this chapter.

16.3.3. Retrieving Multiple Stored Program Result Sets

Unlike other SQL statements, stored programs can return multiple result sets. To access more than one result set, we use the nextset( ) method of the cursor object to move to the next result set.

For instance, suppose that we have a stored procedure that returns two result sets, as shown in Example 16-21.

Example 16-21. Stored procedure that returns two result sets

 

CREATE PROCEDURE sp_rep_report(in_sales_rep_id int) READS SQL DATA BEGIN  SELECT employee_id,surname,firstname FROM employees WHERE employee_id=in_sales_rep_id;  SELECT customer_id,customer_name FROM customers WHERE sales_rep_id=in_sales_rep_id;  END; 

 

To retrieve the two result sets, we fetch the first result set, call nextset( ), then retrieve the second result set. Example 16-22 shows this technique.

Example 16-22. Retrieving two results from a stored procedure

 

cursor=conn.cursor(MySQLdb.cursors.DictCursor) cursor.execute("CALL sp_rep_report(%s)",(rep_id)) print "Employee details:" for row in cursor: print "%d %s %s" % (row["employee_id"], row["surname"], row["firstname"]) cursor.nextset( ) print "Employees customers:" for row in cursor: print "%d %s" % (row["customer_id"], row["customer_name"]) cursor.close( ) 

 

16.3.4. Retrieving Dynamic Result Sets

It's not at all uncommon for stored programs to return multiple result sets and for the result set structures to be unpredictable. To process the output of such a stored program, we need to combine the nextset( ) method with the cursor.description property described in the "Getting Metadata" section earlier in this chapter. The nextset( ) method returns a None object if there are no further result sets, so we can keep calling nextset( ) until all of the result sets have been processed. Example 16-23 illustrates this technique.

Example 16-23. Retrieving dynamic result sets from a stored procedure

 

1 def call_multi_rs(sp): 2 rs_id=0; 3 cursor = conn.cursor( ) 4 cursor.execute ("CALL "+sp) 5 while True: 6 data = cursor.fetchall( ) 7 if cursor.description: #Make sure there is a result 8 rs_id+=1 9 print "\nResult set %3d" % (rs_id) 10 print "--------------\n" 11 names = [] 12 lengths = [] 13 rules = [] 14 for field_description in cursor.description: 15 field_name = field_description[0] 16 names.append(field_name) 17 field_length = field_description[2] or 12 18 field_length = max(field_length, len(field_name)) 19 lengths.append(field_length) 20 rules.append('-' * field_length) 21 format = " ".join(["%%-%ss" % l for l in lengths]) 22 result = [ format % tuple(names), format % tuple(rules) ] 23 for row in data: 24 result.append(format % tuple(row)) 25 print "\n".join(result) 26 if cursor.nextset( )==None: 27 break 28 print "All rowsets returned" 29 cursor.close( ) 

 

Example 16-23 implements a Python function that will accept a stored procedure name (together with any arguments to the stored procedure), execute the stored procedure, and retrieve any result sets that might be returned by the stored procedure.

Let's step through this code:

 

Line(s)

Explanation

2

rs_id is a numeric variable that will keep track of our result set sequence.

34

Create a cursor and execute the stored procedure call. The sp variable contains the stored procedure text and is passed in as an argument to the Python function.

5

Commence the loop that will be used to loop over all of the result sets that the stored procedure call might return.

6

Fetch the result set from the cursor.

7

Ensure that there is a result set from the stored procedure call by checking the value of cursor.description. This is a workaround to a minor bug in the MySQLdbimplementation (version 1.2) in which nextset( ) returns true even if there is no next result set, and only returns False once an attempt has been made to retrieve that null result. This bug is expected to be resolved in an upcoming version of MySQLdb.

1122

Determine the structure of the result set and create titles and formats to nicely format the output. This is the same formatting logic we introduced in Example 16-17.

2325

Print out the result set.

26

Check to see if there is another result set. If there is not, nextset( ) returns None and we issue a break to exit from the loop. If there is another result set, we continue the loop and repeat the process starting at line 6.

28 and 29

Acknowledge the end of all result sets and close the cursor.

 

 

Example 16-24 shows a stored procedure with "dynamic" result sets. The number and structure of the result sets to be returned by this stored procedure will vary depending on the status of theemployee_id provided to the procedure.

Example 16-24. Stored procedure with dynamic result sets

 

CREATE PROCEDURE sp_employee_report (in_emp_id INTEGER, OUT out_customer_count INTEGER) BEGIN  SELECT employee_id,surname,firstname,date_of_birth FROM employees WHERE employee_id=in_emp_id;  SELECT department_id,department_name FROM departments WHERE department_id= (select department_id FROM employees WHERE employee_id=in_emp_id);  SELECT COUNT(*) INTO out_customer_count FROM customers WHERE sales_rep_id=in_emp_id;  IF out_customer_count=0 THEN SELECT 'Employee is not a current sales rep'; ELSE SELECT customer_name,customer_status FROM customers WHERE sales_rep_id=in_emp_id;  SELECT customer_name,SUM(sale_value) as "TOTAL SALES", MAX(sale_value) as "MAX SALE" FROM sales JOIN customers USING (customer_id) WHERE customers.sales_rep_id=in_emp_id GROUP BY customer_name; END IF; END 

 

We can use the Python function shown in Example 16-23 to process the output of this stored procedure. We would invoke it with the following command:

call_multi_rs("sp_employee_report(1,@out_customer_count)") 

 

We pass in 1 to produce a report for employee_id=1; the @out_customer_count variable is included to receive the value of the stored procedure's output parameter (see the next section, "Obtaining Output Parameters"). Partial output from this procedure is shown in Example 16-25.

Example 16-25. Output from a dynamic stored procedure call

 

Result set 1 --------------  employee_id surname firstname date_of_birth ----------- ------- --------- ------------------- 1 FERRIS LUCAS 1960-06-21 00:00:00  Result set 2 --------------  department_id department_name ------------- --------------- 14 KING  Result set 3 --------------  customer_name customer_status ------------------------------- --------------- GRAPHIX ZONE INC DE None WASHINGTON M AAAIswAABAAANSjAAS None 

 

16.3.5. Obtaining Output Parameters

As you know, stored procedures can include OUT or INOUT parameters, which can pass data back to the calling program. The MySQLdb extension does not provide a method to natively retrieve output parameters , but you can access their values through a simple workaround.

Earlier, in Example 16-24, we showed a stored procedure that returned multiple result sets, but also included an output parameter. We supplied a MySQL user variable (prefixed by the @ symbol) to receive the value of the parameter. All we need to do now, in Example 16-26, is to retrieve the value of that user variable using a simple SELECT.

Example 16-26. Retrieving the value of an output parameter

 

call_multi_rs("sp_employee_report(1,@out_customer_count)") cursor2=conn.cursor( ) cursor2.execute("SELECT @out_customer_count") row=cursor2.fetchone( ) print "Customer count=%s" % row[0] cursor2.close( ) 

 

What about INOUT parameters? This is a little trickier, although luckily we don't think you'll use INOUTparameters very much (it's usually better practice to use separate IN and OUT parameters). Consider the stored procedure in Example 16-27.

Example 16-27. Stored procedure with an INOUT parameter

 

CREATE PROCEDURE randomizer(INOUT a_number FLOAT) NOT DETERMINISTIC NO SQL SET a_number=RAND( )*a_number; 

 

To handle an INOUT parameter, we first issue a SQL statement to place the value into a user variable, execute the stored procedure, and then retrieve the value of that user parameter. Code that wraps the stored procedure call in a Python function is shown in Example 16-28.

Example 16-28. Handling an INOUT stored procedure parameter

 

def randomizer(python_number): cursor1=conn.cursor( ) cursor1.execute("SET @inoutvar=%s",(python_number)) cursor1.execute("CALL randomizer(@inoutvar)") cursor1.execute("SELECT @inoutvar") row=cursor1.fetchone( ) cursor1.close( ) return(row[0]) 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、目標 1、目標 代碼編寫規範、整齊、整潔、可讀。 無錯誤 無警告 2、排版 2、排版 安裝PowerCommands擴展 “工具”-“擴展管理庫”,搜索安裝。 設置選中Format document on save和Remove and Sort Usings on save 這樣代碼保存時會自 ...
  • 走進非同步編程的世界 - 剖析非同步方法(下) 序 感謝大家的支持,這是昨天發佈《走進非同步編程的世界 - 剖析非同步方法(上)》的補充篇。 目錄 異常處理 在調用方法中同步等待任務 在非同步方法中非同步等待任務 Task.Delay() 暫停執行 一、異常處理 await 表達式也可以使用 try...cat ...
  • 不知道可能稱的上是ORM,其實就是一個DBHelper。看到網上不少人寫自己的ORM,但我覺得都不太好。 我這個ORM,學習成本非常低,常用的方法僅有幾個,在使用的過程中,你不需要有太多要註意的地方,也不會有“我怎樣實現連表查詢”的疑問。反射犧牲一些性能,但是降低了實現和使用的複雜度。 支持Orac ...
  • 一、前言 MD5驗證主要用於更新文件功能方面,伺服器告知客戶端要下載哪些更新文件並提供給客戶端其MD5值,客戶端從伺服器將更新文件下載到本地並計算下載文件的MD5值,將本地接收的MD5值與伺服器提供的MD5值進行比對,如果相同則說明下載的文件與伺服器提供的文件是一致的,如果不相同則說明下載後文件可能 ...
  • 剛開始學習Halcon,需要使用Halcon與C++聯合開發軟體,查了網上的資料都是Halcon10的,我用的是Halcon11和VS2010的開發環境,實踐了一下發現有一些問題,於是把自己的配置的過程寫出來共用一下。 首先新建一個Halcon工程,這裡用個讀入圖片的簡單例子。 新建一個Halcon... ...
  • 多終端數據同步機制設計(一) Intro 因為項目需要,需要設計一個多終端數據同步的機制, 需要滿足以下條件: 1. 多個終端數據操作及同步 2. 每次同步的時候只拉取需要同步的數據,且數據不能存在丟失 3. 儘可能少的調用伺服器端介面 同步流程 整體同步流程 我想仿照Git數據同步的方式來進行數據 ...
  • php生成隨機密碼(php自定義函數) 導讀:php隨機密碼的生成代碼,使用php自定義函數生成指定長度的隨機密碼,密碼規則為小寫字母與數字的隨機字元串,長度可自定義。 生成一個隨機密碼的函數,生成密碼為小寫字母與數字的隨機字元串,長度可自定義。 複製代碼代碼如下: <?php/* * php自動生 ...
  • 生活的味道 睜開眼看一看窗外的陽光,伸一個懶腰,拿起放在床一旁的水白開水,甜甜的味道,晃著尾巴東張西望的貓貓,在窗臺上舞蹈。你向生活微笑,生活也向你微笑。 請你不要詢問我的未來,這有些可笑。你問我你是不是要找個工作去上班?我告訴你不要,好好享受生活的味道,你所有現在所厭倦的誰說不是別人正羡慕的呢。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...