通过MySQLdb创建函数

ʞɔı*_*ɔıu 15 python mysql

如何在python中使用MySQLdb lib时定义多语句函数或过程?

例:

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 ;""")
Run Code Online (Sandbox Code Playgroud)

这会创建以下回溯:

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")
Run Code Online (Sandbox Code Playgroud)

如果我将相同的SQL直接复制到mysql shell客户端,它会按预期工作

Bil*_*win 20

DELIMITER命令是内置的MySQL shell客户端,只有该程序(和MySQL Query Browser)才能识别它.DELIMITER如果直接通过API执行SQL语句,则无需使用.

当语句本身可以包含分号字符时,目的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
Run Code Online (Sandbox Code Playgroud)

由于API通常允许您一次提交一个SQL语句,因此没有歧义 - 接口知道函数定义主体内的任何分号都不会终止整个CREATE FUNCTION语句.所以没有必要改变语句终止符DELIMITER.


ams*_*ams 9

要添加Bill Karwin的答案,可以使用以下python代码示例来正确执行使用DELIMITER的字符串,例如数据库创建脚本.

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)
Run Code Online (Sandbox Code Playgroud)

这将一次执行一个分隔语句,在需要时更改分隔符.