#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'
(или используйте приведение вместо объединения). Я предлагаю дополнительное сравнение, а не просто замену существующего, чтобы код все еще можно было использовать для поиска по индексу.