Вопрос по выборке данных из БД

verfaa

Профессор
Регистрация
29 Янв 2007
Сообщения
416
Реакции
49
Похожий вопрос я уже задавал тут Для просмотра ссылки Войди или Зарегистрируйся, теперь ситуация обратная - в поле marks хранится только одно число, например 3 или 5.

Из формы приходит массив чисел (юзер отмечает checkbox в форме), т.е. в этом массиве может быть 1 число (юзер отметил только 1 checkbox) или несколько чисел.
Нужно сравнить это число(или числа) с числом в поле marks и занести в выборку строки если числа совпали или одно из чисел из формы совпадает с числом в поле marks.

Например из формы пришли числа 2|5 (массив обработал implode("|", $_REQUEST["gend"]) )
В результате в выборку попадут поля в которых marks равно 2 или 5.
Если из формы пришло 3, в выборку попадут поля в которых marks равно 3.
 
Код:
SELECT * FROM `table` WHERE `id` IN (1, 2, 3);
Выбрать все строки из таблицы, где id = или 1, или 2, или 3

Получить список ID можно через можно использовать implode(',', $array);
Это что касается правильного способа. Есть ещё не правильный:
Код:
SELECT * FROM `table` WHERE `id` = 1 OR `id` = 2 OR `id` = 3);
 
Есть ещё не правильный:
Код:
SELECT * FROM `table` WHERE `id` = 1 OR `id` = 2 OR `id` = 3);
Да, там скобка в конце лишняя.. в остальном - вполне приемлемый (возможно, менее "красивый", чем IN().. но тоже рабочий)

Например из формы пришли числа 2|5 (массив обработал implode("|", $_REQUEST["gend"]) )
.
а если из формы придут буквы? или спецсимволы?

Код:
$gend = $_REQUEST['gend'];
foreach ($gend as $k=>$v)
  $gend[$k] = (int) $v;
$marks = implode(',', $gend);
$q = "SELECT * FROM `table_name` WHERE marks IN ({$marks})";

p.s. если при обращении к базе использовать PDO с bind-ами , проверять тип и экранировать 'кавычки' не обязательно.
 
а если из формы придут буквы? или спецсимволы?

Код:
$gend = $_REQUEST['gend'];
foreach ($gend as $k=>$v)
  $gend[$k] = (int) $v;
$marks = implode(',', $gend);
$q = "SELECT * FROM `table_name` WHERE marks IN ({$marks})";

p.s. если при обращении к базе использовать PDO с bind-ами , проверять тип и экранировать 'кавычки' не обязательно.

А не проще приводить каждый элемент массива к числовому таким способом?
Код:
$array = array_map('intval', $array);

Нашел ещё такую функцию
Код:
function toInteger(&$array, $default = null)
{
    $array = array_map('intval',
    (is_array($array) ? $array : (array) $default));
}

И сразу вопрос, можно без функции обрабатывать массив таким образом?
Код:
$array = array_map('intval', (is_array($array) ? $array : (array) NULL));
 
А не проще приводить каждый элемент массива к числовому таким способом?
Код:
$array = array_map('intval', $array);
Можно и так.. есть ещё filter_var, filter_var_array, filter_input_array.. Как правило, решить задачу можно не одним способом.

Основной упор был на то, что данные от пользователя фильтровать нужно и не стОит использовать вот такое:
Код:
 implode("|", $_REQUEST["gend"])


И сразу вопрос, можно без функции обрабатывать массив таким образом?
А смысл? если он массив, то зачем его на is_array проверять?
 
Все равно SQL запрос не заработал как нужно. Вот как он выглядит целиком, если вывести SQL - запрос на страницу оператором echo:
Код:
SELECT DISTINCT a.id, a.icon_path, e.id_user as session FROM pro_user_match b, pro_user a LEFT JOIN pro_active_sessions e on a.id=e.id_user
WHERE a.gender IN (2,3) AND b.gender regexp '[[:<:]](2)[[:>:]]' AND STRCMP(date_format(a.date_birthday, '%Y%m%d'), date_format('1993-01-01 00:00:00', '%Y%m%d')) <= 0 and STRCMP(date_format(a.date_birthday, '%Y%m%d'), date_format('1973-01-01 00:00:00', '%Y%m%d')) >= 0 and a.id <> '30375'
AND a.icon_path <> '' AND a.id_country = '23' AND a.id_region = '303' AND a.id_city = '1869007' AND b.id_user=a.id and a.status='1' AND a.visible='1' AND a.root_user = '0' AND a.guest_user='0'
ORDER BY a.date_topsearched DESC, a.date_registration DESC

Проблема в следующем: делаю выборку по женщинам и парам м+ж (where a.gender IN (2,3) ) - но в выборку попадают только только пары м+ж (3).
В таблице a.gender - пол юзера, там только числа 1 или 2 или 3 или 4 или 5
В таблице b.gender - пол(-ы) юзеров, которых ищет юзер - та может быть 2 или 5 например, а могут числа через запятую перечислены быть - 2,3,4
 
Вроде разобрался - запрос правильный, просто AND b.gender regexp '[[:<:]](2)[[:>:]]' говорит о том, что нужно добавлять в выборку енщин, которые ищут женщин, а таковых в БД не нашлось))
Далее обнаружил ещё одну проблему, которую сам тоже решить не могу:
При выборке возраста, например от 21 до 23 лет в выборку попадают НЕ ВСЕ 21 летние или НЕ ВСЕ 23-х летние, т.е. НЕ ВСЕ юзеры с начальной или конечной границы заданного возраста.
Видимо ошибка где-то в части
Код:
AND STRCMP(date_format(a.date_birthday, '%Y%m%d'), date_format('1992-01-01 00:00:00', '%Y%m%d')) <= 0
AND STRCMP(date_format(a.date_birthday, '%Y%m%d'), date_format('1990-01-01 00:00:00', '%Y%m%d')) >= 0

в скрипте этот кусок кода выглядит так:
Код:
AND STRCMP(date_format(a.date_birthday, '%Y%m%d'), date_format('".DateFromAge($age_min)."', '%Y%m%d')) <= 0
AND STRCMP(date_format(a.date_birthday, '%Y%m%d'), date_format('".DateFromAge($age_max)."', '%Y%m%d')) >= 0

где переменные в нашем случае равны $age_min = 21 $age_max = 23

функция DateFromAge
Код:
function DateFromAge($age){
    // date in Y-m-d h:i:s format
    $n_year = date("Y");
    $year = $n_year - intval($age);
 
    return strval($year)."-01-01 00:00:00";
}

Помогите пожалуйста разобраться.
 
Вообще, для таких целей завожу числовое поле возраст, которое пересчитывается раз в сутки (и не для всех, а только для тех, у кого ДеньВаренья), а не при каждом поиске...
НЕ ВСЕ 21 летние или НЕ ВСЕ 23-х летние,
...
Код:
    return strval($year)."-01-01 00:00:00";

Ну, возраст-то не у всех прибавляется 1 января
 
так а можно переделать функцию DateFromAge, чтобы она корректно обрабатывала данные?
Всетаки не хотелось бы добавлять новые поля и пересчитывать их каждый день, зачем лишняя нагрузка на БД.
Как тут лучше поступить?
 
какое-то мракобесие у вас с запросом.. непонятно зачем регулярка (это же капец как обузно!) - приведите, пожалуйста, формат поля, с примерами данных.. а лучше полностью схемы таблиц..

ну и даже если с regexp'ом (без которого, скорее всего, можно обойтись), то как-то примерно так:
Код:
SELECT
    DISTINCT a.id,
    a.icon_path,
    e.id_user AS session
FROM pro_user a
    JOIN pro_user_match b ON b.id_user = a.id
    LEFT JOIN pro_active_sessions e
WHERE a.gender IN (2, 3) AND b.gender REGEXP '[[:<:]](2)[[:>:]]'
            AND YEAR( a.date_birthday ) BETWEEN YEAR( NOW() - INTERVAL $age_max YEAR ) AND YEAR( NOW() - INTERVAL $age_min YEAR )
            AND a.id <> '30375'
            AND a.icon_path <> '' AND a.id_country = '23' AND a.id_region = '303' AND a.id_city = '1869007'
            AND a.status='1' AND a.visible='1' AND a.root_user = '0' AND a.guest_user='0'
            ORDER BY a.date_topsearched DESC, a.date_registration DESC;
:
 
Назад
Сверху