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

Тема в разделе "Базы данных", создана пользователем verfaa, 20 авг 2013.

Модераторы: latteo
  1. verfaa

    verfaa

    Регистр.:
    29 янв 2007
    Сообщения:
    371
    Симпатии:
    41
    Похожий вопрос я уже задавал тут https://www.nulled.cc/threads/241394/, теперь ситуация обратная - в поле marks хранится только одно число, например 3 или 5.

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

    Например из формы пришли числа 2|5 (массив обработал implode("|", $_REQUEST["gend"]) )
    В результате в выборку попадут поля в которых marks равно 2 или 5.
    Если из формы пришло 3, в выборку попадут поля в которых marks равно 3.
     
  2. Горбушка

    Горбушка Ищу её...

    Регистр.:
    2 май 2008
    Сообщения:
    3.036
    Симпатии:
    2.037
    Код:
    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);
     
    verfaa нравится это.
  3. esche

    esche

    Регистр.:
    9 авг 2009
    Сообщения:
    360
    Симпатии:
    243
    Да, там скобка в конце лишняя.. в остальном - вполне приемлемый (возможно, менее "красивый", чем IN().. но тоже рабочий)

    а если из формы придут буквы? или спецсимволы?

    Код:
    $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-ами , проверять тип и экранировать 'кавычки' не обязательно.
     
    verfaa и Горбушка нравится это.
  4. verfaa

    verfaa

    Регистр.:
    29 янв 2007
    Сообщения:
    371
    Симпатии:
    41
    А не проще приводить каждый элемент массива к числовому таким способом?
    Код:
    $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));
     
  5. esche

    esche

    Регистр.:
    9 авг 2009
    Сообщения:
    360
    Симпатии:
    243
    Можно и так.. есть ещё filter_var, filter_var_array, filter_input_array.. Как правило, решить задачу можно не одним способом.

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

    А смысл? если он массив, то зачем его на is_array проверять?
     
  6. verfaa

    verfaa

    Регистр.:
    29 янв 2007
    Сообщения:
    371
    Симпатии:
    41
    Все равно 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
     
  7. verfaa

    verfaa

    Регистр.:
    29 янв 2007
    Сообщения:
    371
    Симпатии:
    41
    Вроде разобрался - запрос правильный, просто 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";
    }
    Помогите пожалуйста разобраться.
     
  8. esche

    esche

    Регистр.:
    9 авг 2009
    Сообщения:
    360
    Симпатии:
    243
    Вообще, для таких целей завожу числовое поле возраст, которое пересчитывается раз в сутки (и не для всех, а только для тех, у кого ДеньВаренья), а не при каждом поиске...
    Ну, возраст-то не у всех прибавляется 1 января
     
  9. verfaa

    verfaa

    Регистр.:
    29 янв 2007
    Сообщения:
    371
    Симпатии:
    41
    так а можно переделать функцию DateFromAge, чтобы она корректно обрабатывала данные?
    Всетаки не хотелось бы добавлять новые поля и пересчитывать их каждый день, зачем лишняя нагрузка на БД.
    Как тут лучше поступить?
     
  10. BDSG

    BDSG

    Регистр.:
    28 фев 2009
    Сообщения:
    203
    Симпатии:
    109
    какое-то мракобесие у вас с запросом.. непонятно зачем регулярка (это же капец как обузно!) - приведите, пожалуйста, формат поля, с примерами данных.. а лучше полностью схемы таблиц..

    ну и даже если с 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;
    :