Форматы строк Python с подстановочными знаками SQL и LIKE

Мне сложно заставить sql в python правильно пройти через MySQLdb. Меня убивает форматирование строк в Python.

В моем операторе sql используется ключевое слово LIKE с подстановочными знаками. Я пробовал много разных вещей на Python. Проблема в том, что как только я заставляю один из них работать, в MySQLdb появляется строка кода, которая отрывается от строкового формата.

Попытка 1:

"SELECT tag.userId, count (user.id) as totalRows FROM user INNER JOIN tag ON user.id = tag.userId WHERE user.username LIKE '%% s%'"% (query)

Это бесполезно. Я получаю ошибку значения:

ValueError: неподдерживаемый символ формата '' '(0x27) с индексом 128

Попытка 2:

"SELECT tag.userId, count (user.id) as totalRows FROM user INNER JOIN tag ON user.id = tag.userId WHERE user.username LIKE '\ %% s \%'"% (query)

Тот же результат я получаю с первой попытки.

Попытка 3:

like = "LIKE '%" + str (query) + "%'" totalq = "SELECT tag.userId, count (user.id) as totalRows FROM user INNER JOIN tag ON user.id = tag.userId WHERE user.username "+ нравится

Это правильно создает переменную totalq, но теперь, когда я запускаю запрос, я получаю ошибки от MySQLdb:

Файл "build / bdist.macosx-10.6-universal / egg / MySQLdb / cursors.py", строка 158, в execute query = query% db.literal (args) TypeError: недостаточно аргументов для строки формата

Попытка 4:

like = "LIKE '\%" + str (query) + "\%'" totalq = "ВЫБРАТЬ tag.userId, считать (user.id) как totalRows FROM пользователя INNER JOIN tag ON user.id = tag.userId WHERE user .username "+ лайк

Это тот же результат, что и для попытки 3.

Все это кажется действительно странным. Как я могу использовать подстановочные знаки в операторах sql с Python?


person gngrwzrd    schedule 28.06.2010    source источник
comment
Чтобы повторить @bernie ниже: Из документов psycopg: initd.org/psycopg/docs/: никогда, никогда, НИКОГДА не используйте конкатенацию строк Python (+) или интерполяцию строковых параметров (%) для передачи переменных в строку запроса SQL. Даже под дулом пистолета. Помимо атак с использованием SQL-инъекций, вторым преимуществом является то, что драйвер может автоматически преобразовывать объекты Python в литералы SQL и обратно: с помощью этой функции ваш код будет более устойчивым и надежным. Этот подход по сравнению с наивным подходом к составлению строк запроса, например с использованием конкатенации строк.   -  person Matthew Cornell    schedule 10.06.2013


Ответы (7)


Дело не в форматировании строк, а в том, как запросы должны выполняться в соответствии с требованиями операций с базами данных в Python (PEP 249)

попробуйте что-нибудь вроде этого:

sql = "SELECT column FROM table WHERE col1=%s AND col2=%s" 
params = (col1_value, col2_value)
cursor.execute(sql, params)

вот несколько примеров для psycog2, где у вас есть некоторые пояснения, которые также должны быть действительны для mysql (mysqldb также следует руководству 2.0 API PEP249 dba: вот примеры для mysqldb)

person dzida    schedule 28.06.2010
comment
Спасибо. это сделало это. По какой-то причине я думал, что MySQL db выяснит, как избежать параметров даже внутри оператора sql. Но теперь имеет смысл закинуть параметры вот так. - person gngrwzrd; 28.06.2010
comment
Рад, что помог тебе! Я потратил много времени, пока не понял это некоторое время назад :) - person dzida; 29.06.2010
comment
Как это работает для подстановочных знаков и операторов LIKE в SQL. Я задал тот же вопрос здесь. Я хочу отправить параметры в cursor.execute (), где% s будет использоваться как подстановочный знак и оператор LIKE. - person shreesh katti; 28.03.2019

Все эти запросы кажутся уязвимыми для атак с использованием SQL-инъекций.

Попробуйте вместо этого что-нибудь вроде этого:

curs.execute("""SELECT tag.userId, count(user.id) as totalRows 
                  FROM user 
            INNER JOIN tag ON user.id = tag.userId 
                 WHERE user.username LIKE %s""", ('%' + query + '%',))

Если в execute() передаются два аргумента.

person mechanical_meat    schedule 28.06.2010
comment
Это также выглядит уязвимым для SQL-инъекции. Лучше всего использовать параметризованные запросы через любую библиотеку, которая используется для подключения к базе данных. - person jrdioko; 28.06.2010
comment
@jrdioko: спасибо за ваш комментарий. Обратите внимание, что на самом деле нет интерполяции строк и что запрос подготовлен методом execute(). - person mechanical_meat; 28.06.2010
comment
Я беру это обратно, похоже, что синтаксис - это то, как рассматриваемая библиотека выполняет параметризованные запросы. - person jrdioko; 28.06.2010

Чтобы избежать амперсандов в выражениях форматирования строк Python, удвойте амперсанд:

'%%%s%%' % search_string

Изменить: Но я определенно согласен с другим ответом. Прямая подстановка строк в SQL-запросах - почти всегда плохая идея.

person jrdioko    schedule 28.06.2010
comment
Как использовать то же самое и отправить search_string в качестве параметра функции cursor.execute (). Так что это предотвратит меня от любых SQL-инъекций. - person shreesh katti; 28.03.2019

Мы могли бы попытаться избежать символа процента, удвоив его следующим образом:

query_to_get_user_name = """ 
SELECT tag.userId, count(user.id) as totalRows FROM user INNER JOIN tag 
ON user.id = tag.userId 
WHERE user.username LIKE '%%%s%%' """ % (user_name,) 

cursor.execute(query_to_get_user_name)
person shreesh katti    schedule 28.03.2019

Я попробовал это и думаю, что получил более простой для понимания ответ, школьник. В моем коде имя таблицы - это книги, а столбец, который я ищу, - это имя. Если вам нужно больше разъяснений, напишите письмо на адрес [email protected], и я постараюсь ответить как можно скорее.

def S():

        n=str(input('Enter the name of the book: '))

        name='%'+n+'%'

        NAME=name

        query="select * from books where Name like '"+NAME+"' "

        c.execute(query)

        ans=c.fetchall()
        
        if len(ans)>0:
            print('')

            for i in ans:

                print(i)

             print('')

        else:
            print('')

            print('An error occured')

            print('Name you gave does not exist :( ')

            print('')
person Dhruv Joshi    schedule 07.12.2020

У меня есть решение твоей проблемы:

Нельзя использовать:

"SELECT tag.userId, count(user.id) as totalRows FROM user INNER JOIN tag ON user.id = tag.userId WHERE user.username LIKE '%%s%'" % (query)

вы можете изменить его с помощью строкового шаблона, например:

import MySQLdb
import string # string module
.......
value = {'user':'your value'}
sql_template = string.Template("""
SELECT tag.userId, count(user.id) as totalRows FROM user INNER JOIN
tag ON user.id = tag.userId WHERE user.username LIKE '%$user%'
""")

sql = sql_template.substitute(value)

try:
    cursor.execute(sql)
    ...........
except:
    ...........
finally :
   db.close()
person kamzur    schedule 25.12.2014
comment
Это не лучше, чем прямая подстановка, которую вы в любом случае делать не должны. Заполнители, как описано выше и в документах PEP 249, описывают, как это сделать правильно. - person Turk; 10.04.2017

person    schedule
comment
Было бы намного лучше, если бы вы могли немного рассказать о своем коде и о том, как он решает проблему. - person parisssss; 15.06.2020