Уведомления

Группа в Telegram: @pythonsu

#1 Янв. 29, 2008 09:48:32

securelord
От:
Зарегистрирован: 2006-08-31
Сообщения: 129
Репутация: +  0  -
Профиль   Отправить e-mail  

Будни с MySQLdb

Можно ли заменить такой ужас:

cursor.execute('CALL my_proc ('+'\''+var1+'\', '+'\''+var2+'\', '+'\''+var3+'\', '+'\''+var4+'\'); COMMIT;')
на что нибудь более лаконичное? А то как то стремно такой код кому то показывать :)



Офлайн

#2 Янв. 29, 2008 10:21:05

slivlen
От:
Зарегистрирован: 2006-07-06
Сообщения: 764
Репутация: +  0  -
Профиль   Отправить e-mail  

Будни с MySQLdb

Для вызова процедур у курсора есть функция callproc. Читай доки по DB API 2 и MySQLdb. :)



Офлайн

#3 Фев. 4, 2008 00:12:18

AlexKiriukha
От:
Зарегистрирован: 2008-02-03
Сообщения: 81
Репутация: +  0  -
Профиль   Отправить e-mail  

Будни с MySQLdb

Цитата с http://www.python.org/dev/peps/pep-0249/

.callproc(procname)

(This method is optional since not all databases provide stored procedures. )

Call a stored database procedure with the given name. The sequence of parameters must contain one entry for each argument that the procedure expects. The result of the call is returned as modified copy of the input sequence. Input parameters are left untouched, output and input/output parameters replaced with possibly new values.

The procedure may also provide a result set as output. This must then be made available through the standard fetchXXX() methods.
Конкретно по MySQL примера не нашёл, но есть по Sybase и по идее должно работать и в MySQL.
import sys
import Sybase
db = Sybase.connect(..., auto_commit=True)
db.execute('''
if exists (select name from sysobjects where name = "sp_test_leak")
begin
    drop procedure sp_test_leak
end
''')
db.execute('''
create procedure sp_test_leak
    @arg int
as
    select @arg
''')
for i in range(200):
    for j in range(1000):
        c = db.cursor()
        c.callproc('sp_test_leak', {'@arg': 12345 })
    sys.stdout.write('%3d\r' % i)
    sys.stdout.flush()
sys.stdout.write('\n')
Пример взят с http://coding.derkeiler.com/Archive/Python/comp.lang.python/2005-04/msg01190.html
Для вообще понятия работы в python с MySQL и не только, IMHO стоит просмотреть http://dustman.net/andy/python/python-and-mysql



Отредактировано (Фев. 4, 2008 00:14:17)

Офлайн

#4 Фев. 4, 2008 11:06:47

slivlen
От:
Зарегистрирован: 2006-07-06
Сообщения: 764
Репутация: +  0  -
Профиль   Отправить e-mail  

Будни с MySQLdb

AlexKiriukha
Конкретно по MySQL примера не нашёл, но есть по Sybase и по идее должно работать и в MySQL.
Не факт :) В cx_Oracle н-р совершенно другой стиль передачи аргументов в хранимые процедуры и функции.



Офлайн

#5 Фев. 4, 2008 13:22:03

AlexKiriukha
От:
Зарегистрирован: 2008-02-03
Сообщения: 81
Репутация: +  0  -
Профиль   Отправить e-mail  

Будни с MySQLdb

slivlen
Не факт smile В cx_Oracle н-р совершенно другой стиль передачи аргументов в хранимые процедуры и функции.
Возможно, не сталкивался (как и с MySQL). Поэтому проэкспериментировал. База данных world, которая есть где-то на сайте MySQL, mysql-server-5.0.45, MySQL-python-1.2.2

DELIMITER $$
DROP PROCEDURE IF EXISTS getCitiesForCountry$$
CREATE PROCEDURE getCitiesForCountry(IN countryName CHAR(52))
BEGIN
	SELECT City.Name, City.District, City.Population FROM Country c
		LEFT JOIN City ON c.Code = City.CountryCode
		WHERE c.Name = countryName;
END$$
DELIMITER ;

Вот так работает:
import MySQLdb
db = MySQLdb.connect(db = 'world', host = '127.0.0.1', user = 'root', passwd = 'Hm...')
c = db.cursor()
c.callproc('getCitiesForCountry', ('United Kingdom',))
for row in c:
	print 'Name: %s District: %s Population: %s' % (row[0], row[1], row[2])

Правда в исходниках (файл cursors.py) есть такое замечание:
Compatibility warning: The act of calling a stored procedure
itself creates an empty result set. This appears after any
result sets generated by the procedure. This is non-standard
behavior with respect to the DB-API. Be sure to use nextset()
to advance through all result sets; otherwise you may get
disconnected.



Офлайн

#6 Фев. 4, 2008 13:43:33

slivlen
От:
Зарегистрирован: 2006-07-06
Сообщения: 764
Репутация: +  0  -
Профиль   Отправить e-mail  

Будни с MySQLdb

А как получить значения OUT или INOUT аргументов процедуры?



Офлайн

#7 Фев. 4, 2008 20:08:40

AlexKiriukha
От:
Зарегистрирован: 2008-02-03
Сообщения: 81
Репутация: +  0  -
Профиль   Отправить e-mail  

Будни с MySQLdb

slivlen
А как получить значения OUT или INOUT аргументов процедуры?
Читаем дальше файл cursors.py:
Compatibility warning: PEP-249 specifies that any modified
parameters must be returned. This is currently impossible
as they are only available by storing them in a server
variable and then retrieved by a query. Since stored
procedures return zero or more result sets, there is no
reliable way to get at OUT or INOUT parameters via callproc.
The server variables are named @_procname_n, where procname
is the parameter above and n is the position of the parameter
(from zero). Once all result sets generated by the procedure
have been fetched, you can issue a SELECT @_procname_0, …
query using .execute() to get any OUT or INOUT values
Таким образом (код взят с http://dev.mysql.com/doc/refman/5.0/en/call.html):
DELIMITER $$
DROP PROCEDURE IF EXISTS p$$
CREATE PROCEDURE p (OUT ver_param VARCHAR(25), INOUT incr_param INT)
BEGIN
  # Set value of OUT parameter
  SELECT VERSION() INTO ver_param;
  # Increment value of INOUT parameter
  SET incr_param = incr_param + 1;
END$$
DELIMITER ;
import MySQLdb
db = MySQLdb.connect(db = 'world', host = '127.0.0.1', user = 'root', passwd = 'password')
c = db.cursor()
c.callproc('p', ('', 12))
c.execute('SELECT @_p_0, @_p_1')
for row in c:
	print 'Version: %s Increment: %s' % (row[0], row[1])
Честно говоря не уверен, что это лучший вариант, но так точно работает.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version