У меня есть база данных mysql со столбцом "год", а значения, которые в настоящее время хранятся, составляют 2 и 4 цифры за каждый год, например "18" и "2018".
Я пытаюсь использовать LIKE для возврата записей как для 18, так и для 2018, где пользователь выбирает "2018" в год в форме html.
До сих пор, используя подход ниже, он возвращает только значения для 2018 года, а не значения, в которых данные года хранятся так же, как "18",
Я вижу, что он передает значение "2018", как следует в URL-адресе, и снова, он отлично подходит для возврата результатов, соответствующих 2018.
Вот полный запрос:
$year = $_GET['year'];
$query = "(
SELECT *
FROM test
WHERE ('$name' IS NULL OR '$name' = '' OR name = '$name')
AND ('$city' IS NULL OR '$city' = '' OR city = '$city') AND ('$state' IS NULL
OR '$state' = '' OR state = '$state') AND ('$county' IS NULL OR '$county'
= '' OR county = '$county') AND ('$year' IS NULL OR '$year' = ''
OR year LIKE '%$year%') AND ('$month' IS NULL OR '$month' = '' OR
month = '$month')order by name)";
$year = 18;
select * from test where year LIKE '$year%'; //OUTPUTS YEAR STARTS WITH 18
select * from test where year LIKE '%$year'; //OUTPUTS YEAR ENDS WITH 18
select * from test where year LIKE '%$year%'; //OUTPUTS YEAR WITH PATTERN OF 18
Ваши данные просто сломаны. Вы должны были нормализовать данные перед их сохранением в базе данных.
Это несколько нормально, если вы хотите, чтобы ваши пользователи имели некоторую свободу при вводе. Однако у вас нет такой роскоши в базе данных. Чтобы восстановить ввод пользователя, вы можете использовать функцию/метод:
function normaliseYear(int $year): int
{
if (999 < $year && $year < 10000) {
// Year is already normalised
return $year;
}
if (0 <= $year && $year < 100) {
// Got the year within the century, assume 21. century
return 2000 + $year;
}
// You can put other repairable cases here
// Got something we can not repair
throw new UnexpectedValueException("Unable to normalise $year as a year");
}
Вы используете эту функцию/метод как для создания и извлечения данных, поэтому ваша база данных чистая, а запросы остаются простыми (= быстро).
Поскольку у вас уже есть "плохие" данные в вашей базе данных, вам необходимо их восстановить. На самом деле вам нужно сделать такую же нормализацию по существующим данным, но, к счастью, только один раз.
UPDATE test SET year = 2000 + year WHERE year < 100;
Тогда ваш запрос будет выглядеть так:
$year = ($year === '' || $year === null) ? null : normaliseYear((int)$_GET['year']);
// Do not forget to sanitise user input!
$month = (int)$month;
// ...
$skipName = empty($name) ? 1 : 0;
$skipCity = empty($city) ? 1 : 0;
$skipState = empty($state) ? 1 : 0;
$skipCounty = empty($county) ? 1 : 0;
$skipYear = ($year === null) ? 1 : 0;
$skipMonth = empty($month) ? 1 : 0;
$query = "(
SELECT *
FROM test
WHERE ($skipName OR name = '$name')
AND ($skipCity OR city = '$city')
AND ($skipState OR state = '$state')
AND ($skipCounty OR county = '$county')
AND ($skipYear OR year = $year)
AND ($skipMonth OR month = $month)
ORDER BY name
)";
Я нашел, что ваш пользователь выбирает 2018, и вы используете как на 2018 год только в том виде, в котором ваш код предлагает:
$ year = $ _GET ['year'];
Я предлагаю вам передать только 2 символа в переменную $ year, и все будет хорошо.
Вы можете "нормализовать" year
с year % 100 + 2000
. Поэтому, если вы ищете 2018
, это условие будет
year % 100 + 2000 = 2018
Это будет соответствовать: year = 18
и year = 2018
. Но и year = 118
.
Обратите внимание, что NULL
будет преобразован в пустую строку в PHP. Так что-то вроде '$name' IS NULL
никогда не произойдет. И вы можете упростить свой запрос:
SELECT *
FROM test
WHERE '$name' IN ('', name)
AND '$city' IN ('', city)
AND '$state' IN ('', state)
AND '$county' IN ('', county)
AND '$year' IN ('', year % 100 + 2000)
AND '$month' IN ('', month)
order by name
И вы должны использовать подготовленный оператор с заполнителями вместо того, чтобы вводить небезопасные переменные в строку запроса.