Запрос выбора MySQL предполагает, что 1623x = 1623 является истинным

#mysql #sql #string #where-clause

#mysql — сервер #sql #строка #where-предложение #mysql

Вопрос:

Кто-нибудь знает, почему этот запрос возвращает результаты, когда этого не должно быть? Код в запросе имеет дополнительный x, но код в базе данных его не имеет.

 SELECT * FROM `otp` WHERE `code`= '1623x' AND `userid`='4' AND `status`='1'
  

введите описание изображения здесь

Заранее спасибо…

Morgs

Ответ №1:

 WHERE `code`= '1623x' 
  

Я сильно подозреваю, что code это числовой столбец.

Если это так: чтобы оценить условие, MySQL должен сравнить число со строкой. Что он делает, так это преобразует строку в число, а затем выполняет числовое сравнение. Оказывается, что строка '1623x' преобразуется в число 1623 , поэтому условие выполнено.

Если бы, например, строка была 'x1623' , она была бы преобразована в 0 (потому что она не начинается с цифры), и вы бы не получили никакого результата.

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

Комментарии:

1. @Morgs: добро пожаловать. Обратите внимание, что это также относится к другим условиям в where предложении, поскольку user_id и status также, вероятно, являются целочисленными столбцами. Итак: where code = 1623 AND userid = 4 AND status = 1 .

2. «не делайте этого» — не очень привлекательное решение. это означает, что при использовании пользовательского ввода вам приходится выполнять дополнительную работу в предположительно редких случаях неправильного ввода, чтобы убедиться, что он имеет правильный тип. лучше просто сделать это как часть запроса IMO

3. @ysth Я интерпретирую комментарий GMB просто как общее предупреждение, чтобы даже не оказаться в ситуации, когда строки сравниваются с целыми числами. Предполагая, что этот запрос генерируется чем-то вроде PHP-скрипта, тогда OP должен гарантировать, что в RHS сравнения используются только целые числа.

4. @GMB верно, у меня есть общий, db_helper который добавляет » к каждому значению столбца, и на данный момент я не могу узнать тип столбца в БД. Но мне придется как-то заново изобрести колесо, поскольку я предполагаю, что я даю базе данных дополнительную работу по приведению / анализу значений..

5. @Morgs Если я вас правильно понимаю, добавление » к каждому значению столбца может просто отключить вашу индексацию — вы действительно не хотите этого делать

Ответ №2:

То, что вы видите, связано с особыми правилами приведения MySQL. Когда вы пытаетесь сравнить строковый литерал '1623x' с целым 1623 числом, MySQL должен что-то сделать, чтобы сначала привести LHS и RHS к одному и тому же типу. Единственный способ сделать это — привести '1623x' к целому числу. Правила приведения таковы, что если строка начинается с целого числа, то MySQL сохранит столько цифр, сколько доступно. В этом случае, '1623x' становится целым 1623 , и поэтому LHS и RHS становятся истинными.

Чтобы было ясно, вот запрос, который оценивается для получения неожиданной записи:

 SELECT *
FROM otp
WHERE 1623 = 1623 AND userid = 4 AND status = 1;
  

Ответ №3:

MySQL использует тип правого операнда для приведения левого операнда. Если у вас есть столбец целочисленного типа code и вы говорите code = '123abc' , это становится эквивалентным code = 123 (с предупреждением). Если вы хотите предотвратить это (а также такие вещи, как code = '00123' или code = '123.0' ) от нахождения 123, добавьте дополнительное условие where, чтобы также выполнить сравнение строк:

 and code='123abc' and concat(code)='123abc'
  

(или используйте приведение вместо объединения). Я предлагаю дополнительное сравнение, а не просто замену существующего, чтобы код все еще можно было использовать для поиска по индексу.