2009-04-13 58 views
13

創建功能我如何定義使用python中MySQLdb的LIB多語句函數或過程?通過MySQLdb的

例子:

import MySQLdb 

db = MySQLdb.connect(db='service') 

c = db.cursor() 

c.execute("""DELIMITER // 
CREATE FUNCTION trivial_func (radius float) 
    RETURNS FLOAT 

    BEGIN 
    IF radius > 1 THEN 
     RETURN 0.0; 
    ELSE 
     RETURN 1.0; 
    END IF; 
END // 

DELIMITER ;""") 

它創建以下回溯:

Traceback (most recent call last): 
    File "proof.py", line 21, in <module> 
    DELIMITER ;""") 
    File "build/bdist.macosx-10.5-i386/egg/MySQLdb/cursors.py", line 173, in execute 
    File "build/bdist.macosx-10.5-i386/egg/MySQLdb/connections.py", line 35, in defaulterrorhandler 
_mysql_exceptions.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER //\nCREATE FUNCTION trivial_func (radius float) \n RETURNS FLOAT\n\n ' at line 1") 

如果我直接複製相同的SQL到MySQL殼客戶端,它按預期工作

回答

17

DELIMITER命令是一個MySQL shell客戶端內置的程序,只有該程序(和MySQL Query Browser)才能識別它。如果您直接通過API執行SQL語句,則不需要使用DELIMITER

DELIMITER的目的是幫助您避免語句本身可以包含分號字符時終止CREATE FUNCTION語句的歧義。這在shell客戶端很重要,默認情況下分號終止SQL語句。您需要將語句終結符設置爲其他字符以提交函數(或觸發器或過程)的主體。

CREATE FUNCTION trivial_func (radius float) 
    RETURNS FLOAT 

    BEGIN 
    IF radius > 1 THEN 
     RETURN 0.0; <-- does this semicolon terminate RETURN or CREATE FUNCTION? 
    ELSE 
     RETURN 1.0; 
    END IF; 
END 

由於API通常會允許你在一個時間提交一個SQL語句,沒有歧義 - 接口知道你的函數定義的體內任何分號不終止整個CREATE FUNCTION聲明。所以沒有必要用DELIMITER來更改語句終止符。

+0

,除非你需要。例如運行數據庫創建腳本。有沒有辦法將原始SQL傳遞給MySql? – 2012-05-15 14:50:14

+0

@BryanHunt,你無法通過動態SQL API提交一個SQL腳本,因爲幾個命令只能由`mysql`客戶端,而不是服務器的SQL語法分析器認可。 – 2012-05-15 22:05:33

4

要添加到由Bill Karwin答案,下面的Python代碼示例可用於正確執行在使用分隔符字符串,如數據庫創建腳本。

import MySQLdb 

db = MySQLdb.connect(db='service') 
cursor = db.cursor() 

dbString = """DELIMITER // 
CREATE FUNCTION trivial_func (radius float) 
RETURNS FLOAT 

BEGIN 
IF radius > 1 THEN 
    RETURN 0.0; 
ELSE 
    RETURN 1.0; 
END IF; 
END // 

DELIMITER ;""" 

# Find special delimiters 
delimiters = re.compile('DELIMITER *(\S*)',re.I) 
result = delimiters.split(dbString) 

# Insert default delimiter and separate delimiters and sql 
result.insert(0,';') 
delimiter = result[0::2] 
section = result[1::2] 

# Split queries on delimiters and execute 
for i in range(len(delimiter)): 
    queries = section[i].split(delimiter[i]) 
    for query in queries: 
     if not query.strip(): 
      continue 
     cursor.execute(query) 

這一次執行一個分隔的語句,在需要時改變分隔符。

0

基於從@AaronS評論。這個腳本將讀取一個SQL文件,將其分割成離散的SQL命令並處理它找到的任何分隔符。

queries = [] 
    delimiter = ';' 
    query = '' 
    with open('import.sql', 'r') as f: 
     for line in f.readlines(): 
      line = line.strip() 
      if line.startswith('DELIMITER'): 
       delimiter = line[10:] 
      else: 
       query += line+'\n' 
       if line.endswith(delimiter): 
        # Get rid of the delimiter, remove any blank lines and add this query to our list 
        queries.append(query.strip().strip(delimiter)) 
        query = '' 

    for query in queries: 
     if not query.strip(): 
      continue 
     cursor.execute(query) 
    cursor.close()