Mam problem z wstawianiem zmiennych do łańcucha SQL. Przykład choćby na
tak banalnym pliku:
import MySQLdb
MySQLdb.paramstyle = "format"
db = MySQLdb.Connect(host="localhost", port=3306, user="root",
passwd="root", db="monitor")
cur = db.cursor()
cur.execute("SELECT * FROM %%s", ("routers",))
print cur.fetchone()
wywala błąd:
Traceback (most recent call last):
File "ser.py", line 6, in <module>
cur.execute("SELECT * FROM %%s", ("routers",))
File "build/bdist.linux-i686/egg/MySQLdb/cursors.py", line 158, in
execute
TypeError: not all arguments converted during string formatting
Już próbowałem z paramstyle. Nawet wywaliłem kodowanie bo myślałem, że
to może być przyczyną. Jednak cały czas nie o to chodzi. Nie za bardzo
wiem czego dalej mogę szukać. Czy ktoś spotkał się z taką sytuacją?
> cur.execute("SELECT * FROM %%s", ("routers",))
^^^
tylko jeden znak %
Jeśli nie używasz operatora %, to znak '%' w łańuchu nie
zyskuje specjalnego znaczenia. Zobacz sobie co się wyświetli:
wzorzec = 'test=%s'
print wzorzec # => 'test=%s'
print wzorzec % 'test' # => 'test=test'
w.
cur.execute("SELECT * FROM routers")
wykonuje si� bez problem�w tymczasem po wywaleniu tego jednego procenta
linijka:
cur.execute("SELECT * FROM %s", ("routers",))
wywala b��d:
_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 ''routers'' at line 1")
Z tego co sprawdzi�em b��d mysql 1064 oznacza z�e u�ycie s��w
kluczowych. I dalej nie za bardzo potrafi� to przypi�� do czego�.
OK dzia�a tylko jak dam:
cur.execute("SELECT * FROM %s" % "routers")
Ale powinno tak�e dzia�a� w wariancie z dwoma argumentami z czego drugi
powinien by� tupl�. Dla innych paramstyle'�w pr�bowa�em i by� podobny
skutek. Czy�bym �le u�ywa� funkcji execute? Czy�bym �le rozumia�
filozofi� stosowania oddzielnie zapytania i oddzielnie argument�w zapytania?
cur.execute("SELECT * FROM %s" % (tupla_argument�w))
Wstyd mi za siebie :)
W przypadku cur.execute("SELECT * FROM %s", ("routers",)) próbujesz
przemycić nazwę obiektu jako parametr zapytania (napis), co daje efekt jak
mysql> SELECT * FROM "routers"; -- ERROR 1064
zamiast
mysql> SELECT * FROM routers; -- OK
.pk.
IMHO tak :). W Oracle PLSQL te� mi nie zadzia�a:
SELECT * FROM :table_name
a zadzia�a
SELECT * FORM tabele WHERE kolumna = :value
Co jest o tyle logiczne, �e zmienne wi�zane to nie tylko "elegancja" i
zabezpieczenie przed SQL injection, ale r�wnie� optymalizacja zapytania po
stronie silnika bazy danych. Wynik polecenia ze nieokre�lon� nazw� kolumny
lub tabeli nie nadaje siďż˝ do cache. Ze zmiennymi w klauzuli WHERE - tak.
> IMHO tak :). W Oracle PLSQL te� mi nie zadzia�a:
>
> SELECT * FROM :table_name
>
> a zadzia�a
>
> SELECT * FORM tabele WHERE kolumna = :value
>
> Co jest o tyle logiczne, �e zmienne wi�zane to nie tylko "elegancja" i
> zabezpieczenie przed SQL injection, ale r�wnie� optymalizacja zapytania
> po stronie silnika bazy danych. Wynik polecenia ze nieokre�lon� nazw�
> kolumny lub tabeli nie nadaje siďż˝ do cache. Ze zmiennymi w klauzuli
> WHERE - tak.
Teraz poj��em ca�kowicie ten mechanizm. Po prostu czytaj�c dokumentacj�
MySQLdb stoi jak byk:
Parameter placeholders can only be used to insert column values. They
can not be used for other parts of SQL, such as table names, statements,
etc.
Wi�c gdy si� chce odnosi� do czego� innego ni� do warto�ci kolumn to
muszďż˝ to robiďż˝ przez proste pythonowe podstawienie zmiennej do stringa a
nie przez funkcjďż˝ dwuparametrowďż˝ execute()
Tak jest. I co wi�cej, te parametry przekazane do execute, nie s� wi�zane z
SQLem ani przez bibliotekďż˝ Pythona ani przez klienta bazy danych tylko
gdziďż˝ po drugiej stronie przez sam motor bazy.