Создать функцию через MySQLdb
Как я могу определить функцию или процедуру многозадачности при использовании MySQLdb lib в python?
Пример:
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, он работает как ожидалось
Ответы
Ответ 1
Команда DELIMITER
- это встроенный клиент оболочки MySQL, и он распознается только этой программой (и MySQL Query Browser). Нет необходимости использовать DELIMITER
, если вы выполняете SQL-инструкции непосредственно через API.
Цель DELIMITER
- помочь вам избежать двусмысленности в отношении завершения инструкции CREATE FUNCTION
, когда сам оператор может содержать символы с запятой. Это важно в клиенте оболочки, где по умолчанию точка с запятой завершает инструкцию 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
.
Ответ 2
Чтобы добавить к ответу Билла Карвина, следующий пример кода python можно использовать для правильного выполнения строки, в которой используется DELIMITER, например создания базы данных script.
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)
Это будет выполнять один разграниченный оператор за раз, изменяя при необходимости разделители.
Ответ 3
Основываясь на комментарии от @AaronS. Этот script будет читать в файле 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()