Модераторы: skyboy, MoLeX, Aliance, ksnk

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> сформировать запрос по значениям для трех полей, каждое из них может не быть задано 
:(
    Опции темы
Denwer
Дата 3.12.2009, 01:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 91
Регистрация: 19.6.2007
Где: Харьков

Репутация: нет
Всего: нет



Есть табличка с тремя полями (f1,f2,f3)

Есть 3 раскрывающих списка на сайте, которые содержат такие же значения как и в таблице.

Как организовать поиск? понятно что если я выберу значения во всех
трех списках запрос будет идти так

$query = "SELECT * FROM ".TABLE_USERS." WHERE f1='$z1' AND f2='$z2' AND f2='$z3'";

если скажем я выберу значение только в первом списке то запрос таков
$query = "SELECT * FROM ".TABLE_USERS." WHERE f1='$z1''";

Вариантов выбора получается 9. Не делать же мне кучу проверок на то какие списки я выбрал и следовательно к ним запрос. А если будет 5 полей, то головоломка увеличиться на 5 в квадрате

Может кто сталкивался или знает как решить проблему, или знает того кто знает

ПОМОГИТЕ !!! 



Это сообщение отредактировал(а) Denwer - 3.12.2009, 01:12
PM WWW   Вверх
Pitlord
Дата 3.12.2009, 01:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 246
Регистрация: 31.10.2009

Репутация: 4
Всего: 7



PM MAIL   Вверх
Aumn
Дата 5.12.2009, 05:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 15
Регистрация: 3.12.2009

Репутация: нет
Всего: нет



Цитата(Pitlord @  3.12.2009,  01:14 Найти цитируемый пост)
http://forum.vingrad.ru/forum/topic-281107...y2027781/0.html


Неплохое решение, но на мой взгляд слишком уж громоздкое. Он к сути и сводится к тому, что при увеличении кол-ва полей увеличивается кол-во строк обработки. Я предлагаю следующий вариант. С условием того, что у Вас все названия полей имеют идентичный вид (что упрощает реализацию собственно), можно проверить на заполненность и составить запрос небольшим циклом.

Код

//обнуляем переменную, если она уже была созданна раннее
$q = "";
//проверяем все переменные на заполненность
for($i = 1;$i <= 3;$i++) {
if (!empty(${f.$i}) {
  if(!empty($q)) {
    $q .= " AND `{f.$i}`='${z.$i}'";
  }
  else {
    $q .= "`{f.$i}`='${z.$i}'";
}
//формируем запрос из условия - заполненно хотя бы 1 поле. В случае, если поля не заполнены, выводим все данные таблицы
if(!empty($q)) $query = "SELECT * FROM ".TABLE_USERS." WHERE ".$q; else $query = "SELECT * FROM ".TABLE_USERS;


Вместо тройки вставляете необходимое Вам значение кол-ва полей.

Это сообщение отредактировал(а) Aumn - 5.12.2009, 05:15
PM MAIL ICQ Skype   Вверх
MaXL
Дата 5.12.2009, 06:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Developer
**


Профиль
Группа: Участник
Сообщений: 380
Регистрация: 24.10.2005
Где: Владивосток

Репутация: нет
Всего: 2



Я так понял необходимые поля в БД текстовые.
А что если не выбранным полям присвоить значение %. И тогда просто сформировать запрос следующим образом:
Код

$query = "SELECT * FROM ".TABLE_USERS." WHERE f1='$z1' AND f2='$z2' AND f2='$z3'";



--------------------
MaXL
PM MAIL   Вверх
Aumn
Дата 5.12.2009, 07:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 15
Регистрация: 3.12.2009

Репутация: нет
Всего: нет



К сожалению, я тут помочь Вам не могу, так как не знаю структуру БД и поля (тип, вводимая информация и т.д.) Я проверил свой код, он работает для любого числа полей и типа вводимой информации. Поэтому если вы дадите полные данные, возможно я свогу Вам помочь.
PM MAIL ICQ Skype   Вверх
Ипатьев
Дата 5.12.2009, 09:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2232
Регистрация: 5.7.2009

Репутация: 28
Всего: 37



MaXL, боюсь, такой запрос не вернет ничего.

Aumn, у вас в таблице поля всегда так называются - буква с цифрой? Если нет - то к чему изобретать такой заведомо нежизнеспособный код?
Разрешите дать вам один совет. Как человеку, который решил отвечать на вопросы оптом, даже не глядя на дату последнего сообщения. 
Пишите код только в том случае, если вы уже использовали его раньше, в сходной ситации. А не придумывая его на ходу.
PM MAIL   Вверх
Simpliest
Дата 5.12.2009, 12:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 625
Регистрация: 1.9.2009

Репутация: 1
Всего: 3



Вариант номер раз.

Код

    $_POST = array('brand' => 'KU\KU',
                   'lamp' => "Don't");
    // ключ - id входных данных с формы
    // значение - условие
    $allowed =  array('brand'         => 'brand = :?',
                          'lamp'      => 'lamp = :?',
                          'status'        => 'status = :?',
                          'supplier_id'   => 'supplier_id = :?',
                          'product_id'    => 'product_id NOT LIKE :?',
                          'location_id'   => 'location_id LIKE :?',
                          'company_id'    => 'company_id LIKE :?'
    );
    // создаем массив условий только для тех значений которые у нас есть и во входных данных, и в массиве с критериями
    $clause = _makeClause($_POST, $allowed);
    // эскейпим и подставляем значения в плейсхолдеры
    array_walk(&$clause,
            create_function('&$value, $condition',
            '$value = str_replace(":?", "\'" . mysql_real_escape_string($value) . "\'", $condition);
            return true;'));
    // итоговое условие
    $clause = implode(' ',     $clause);
    echo $clause;

    protected function _makeClause($values, $allowed)
    {
        $clause = array();
        foreach ($values as $key => $val) {
            if (array_key_exists($key, $allowed)) {
                if (null != $val) {
                    $clause[$allowed[$key]] = $val;
                }
            }
        }
        return $clause;
    }


Извращение номер два'с
Код

// эталон условия 
echo "c = 1 and (d > 2.78e02 or c in (1,2,3) and not (t ='2.78d02'  or (c = 4))) or (d = 1 and (c = 2 or d = 2)) or (c = Mech's are not\listed) and (d = Mech's\twork)";
// оно же в виде массива
$c = array(
    'c =:?' => 1,
    'and' => array(
        'd >:? or ' => '2.78e02',
        'c in' => array(1,2,3),
        'and not' => array(
            't =:?' => '2.78d02',
            'or' => array('c =:?' => 4)
        )
        ),
        array (
            'or' => array (
                'd =:? ' => 1,
                'and' => array(
                    'c =:? or' => 2,
                    array('d =:?' => 2)
                )
            )
        ),
        array(
            'or' => array('c =:?' =>  "Mech's are not\listed")
        ),
     array('and' => array('d =:?' => "Mech's\twork"))
);
echo '<hr>';
echo whereBuilder($c);
die();

function whereBuilder(array $condition) {
    $where = '';
    foreach ($condition as $criteria => $value) {
        if (substr(strtolower($criteria), -3) == ' in') {
            $where .= ' ' . $criteria . " (" . implode(",", array_map(create_function('$a','return is_numeric($a) ? $a : "\'" . $a . "\'";'), array_map('mysql_real_escape_string',(array) $value))) . ")";
        } elseif (is_array($value)) {
            // если вместо значения массив то обрабатываем вложенные условия
            // если критерий/условие целое число, отбрасываем его. Сделано для избежания коллизий ключей для множественных равнозначных условий
            is_int($criteria) ?
            $where .= ' ' . whereBuilder($value) . '' :
            $where .= ' ' . $criteria . ' (' . whereBuilder($value) . ')' ;
        } elseif(false !== strpos($criteria, ':?')) {
            // эскейпим и подставляем значение в условие
            $where .= ' ' . str_replace(':?', is_numeric($value = mysql_real_escape_string($value)) ? $value : '\'' . $value . '\'', $criteria) . ' ';
        } else {
            // хардкод критерии випа D = "1" всегда. $value - необязателен
            $where .= ' ' . $criteria . (is_numeric($value) ? $value:'\'' . ($value) . '\'') ;
        }
    }
    return $where;
}


А вообще это все глупости smile нужно использовать биндинг и не заниматься подстановкой в запросы.


--------------------
user posted image
PM   Вверх
Ипатьев
Дата 5.12.2009, 12:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2232
Регистрация: 5.7.2009

Репутация: 28
Всего: 37



в итоге код получился немного больше, чем в варианте Pitlord-а. и в разы сложнее. затрудняя отладку и чтение
а можно посмотреть пример, как биндинг решает данную проблему?


Это сообщение отредактировал(а) Ипатьев - 5.12.2009, 12:27
PM MAIL   Вверх
Simpliest
Дата 5.12.2009, 13:16 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 625
Регистрация: 1.9.2009

Репутация: 1
Всего: 3



Цитата(Ипатьев @  5.12.2009,  11:13 Найти цитируемый пост)
а можно посмотреть пример, как биндинг решает данную проблему?

Отладку и чтение? smile

Код

protected function _buildStmt($sql, $data, $allowedCriteria) {
    $valuesToBind = array();

    $sql .= '1=1 AND ';

    foreach ($data as $key => $val) {
        if (array_key_exists($key, $allowedCriteria)) {
            if (null != $val) {
                $sql.= ' ' . $allowedCriteria[$key];
                $valuesToBind[] = $val;
            }
        }
    }
    $sql = substr($sql, -5);

    if($stmt = $this->prepare($sql)) {
        foreach($valuesToBind as &$param) {
            $stmt->bind_param('s', $param);
        }
    }
    return $stmt;
}


Добавлено через 13 минут и 11 секунд
Цитата(Ипатьев @  5.12.2009,  11:13 Найти цитируемый пост)
в итоге код получился немного больше, чем в варианте Pitlord-а

Если имеется в виду Извращение номер два'с
то это именно извращение, которое никогда никому не потребуется и не может быть применено. Хотя и рабочее smile

Первый же вариант за исключением части с array_walk & mysql_real_escape_string я использовал раньше очень часто.

Он легко справляется и с десятками полей smile Читаться будет так же как и сейчас.
В варианте Pitlord-а придется по-копипастить. Да и не люблю я тридацать раз писать одни и те же if smile
мне массив приятнее.




--------------------
user posted image
PM   Вверх
Ипатьев
Дата 5.12.2009, 14:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2232
Регистрация: 5.7.2009

Репутация: 28
Всего: 37



Цитата(Simpliest @  5.12.2009,  13:16 Найти цитируемый пост)
Отладку и чтение?

Нет. проблему, в связи с короторй биндинг был заявлен: не заниматься подстановкой в зпросы.
В это связи я не очень понимаю, чем является выражение  $sql.= ' ' . $allowedCriteria[$key]
$sql - это не запрос?

я всегда считал, что имена полей, условия, и - тем более - функции mysql в подстановках исползовать нельзя.

Цитата(Simpliest @  5.12.2009,  13:16 Найти цитируемый пост)
В варианте Pitlord-а придется по-копипастить. Да и не люблю я тридацать раз писать одни и те же if 

проблема в том, что в реальной жизни этот иф чаще всего совсем не один и тот же.
и копипастить придется совсем немного. 

при этом код будет понятным и читаемым. 
стремление к чрезмерной абстракции столь же губительно, как и преждевременная оптимизация.
PM MAIL   Вверх
Simpliest
Дата 5.12.2009, 15:21 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 625
Регистрация: 1.9.2009

Репутация: 1
Всего: 3



Цитата(Ипатьев @  5.12.2009,  13:20 Найти цитируемый пост)
не заниматься подстановкой в зпросы.

Дык.
Сравнить эту лажу
Цитата(Simpliest @  5.12.2009,  11:06 Найти цитируемый пост)
 str_replace(':?', is_numeric($value = mysql_real_escape_string($value)) ? $value : '\'' . $value . '\'', $criteria)

и биндинг
Цитата(Simpliest @  5.12.2009,  12:16 Найти цитируемый пост)
$stmt->bind_param('s', $param);

И все станет очевидно.

Цитата(Ипатьев @  5.12.2009,  13:20 Найти цитируемый пост)
В это связи я не очень понимаю, чем является выражение  $sql.= ' ' . $allowedCriteria[$key]

это формирование условия к запросу из списка разрешенных полей.
Нам могут прийти не все поля, пользователь может иметь доступ не ко всем полям и т.д.

Цитата(Ипатьев @  5.12.2009,  13:20 Найти цитируемый пост)
проблема в том, что в реальной жизни этот иф чаще всего совсем не один и тот же

? в честь чего? Валидация и фильтрация лежат несколько в отдельном месте. А проверка на наличие/разрешенность поля... будет одинаковой.

Цитата(Ипатьев @  5.12.2009,  13:20 Найти цитируемый пост)
и копипастить придется совсем немного. 
при этом код будет понятным и читаемым. 

Примерчик кода нет желания привести?
Мой опыт говорит, что копипаста будет очень много и код быстро превратиться в лапшу.

Цитата(Ипатьев @  5.12.2009,  13:20 Найти цитируемый пост)
стремление к чрезмерной абстракции столь же губительно, как и преждевременная оптимизация. 

Я так понимаю пример конкретной системы, конкретной чрезмерной абстракции и конкретной ее реализации, привести не затруднит?


--------------------
user posted image
PM   Вверх
Ипатьев
Дата 5.12.2009, 15:37 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2232
Регистрация: 5.7.2009

Репутация: 28
Всего: 37



Мне кажется, что вы говорите о чем угодно, но только не о конкретной проблеме составления запроса по множесту критериев.
Какая разница, как мы подставляем в запрос само значение, если в данном случае мы подставляем не значение, а целиком условие?
как bind_param поможет составить выражение вида
date(start) > '2009-11-11'
где 2009-11-11 берется из формы?
зачем городить сложную систему, распознающую миллиард различных комбинаций условий, если эти условия можно просто написать вручную?

Цитата(Simpliest @  5.12.2009,  15:21 Найти цитируемый пост)
Я так понимаю пример конкретной системы, конкретной чрезмерной абстракции

На самом деле я хотел предложить именно это. привести примеры реальных задач. 
Но вы, мне кажется, не понимаете, о чем пишете. пример чрезмерной абстракции у меня просить не надо. Во-первых, у меня его, по очевидным причинам, нету. А во-вторых, пример есть в этом топике, парой сообщений выше.
PM MAIL   Вверх
Simpliest
Дата 5.12.2009, 16:14 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 625
Регистрация: 1.9.2009

Репутация: 1
Всего: 3



Цитата(Ипатьев @  5.12.2009,  14:37 Найти цитируемый пост)
Мне кажется, что вы говорите о чем угодно, но только не о конкретной проблеме составления запроса по множесту критериев.
Какая разница, как мы подставляем в запрос само значение, если в данном случае мы подставляем не значение, а целиком условие?

Брр. Не путайте теплое с мягким.

Построение запроса и подстановку/биндинг параметров (последний вообще возможен только к готовому запросу, а не куску условия)

Опыт работы с ОРМ или хотя бы с DBAL проектов отличных от сайтов-визиток хоть какой-нибудь вообще имеется? Чтобы я просто понимал ваш уровень в этом вопросе.

Цитата(Ипатьев @  5.12.2009,  14:37 Найти цитируемый пост)
зачем городить сложную систему, распознающую миллиард различных комбинаций условий, если эти условия можно просто написать вручную?

Не воюйте с ветряными мельницами - это неперспективно. Вы выдумали себе мельницу и доблестно пытаетесь ее разбить.

Вот это еще не ###код, но крайне близкое к нему решение.
Цитата(Pitlord @  22.11.2009,  21:02 Найти цитируемый пост)
Код

if( $name != '' )
    $fields[] = '`name` = "' . mysql_real_escape_string($name) . '"';
...



Вот это откровенный ###код.
Цитата(Simpliest @  5.12.2009,  11:06 Найти цитируемый пост)
Код

echo whereBuilder($c);
die();

function whereBuilder(array $condition) {
...


Связывать построение запроса и подстановку/биндинг данных в линейном коде - не самое лучшее решение для проекта (для разового скрипта подойдет и лапша).
Чрезмерно усложнить решение простой задачи - тоже глупость.

Цитата(Ипатьев @  5.12.2009,  14:37 Найти цитируемый пост)
Во-первых, у меня его, по очевидным причинам, нету

Вы не пишите вовсе? Или пишите исключительно "лапшу"? Это печально.
Смею уверить, если бы вы хоть что-то сложное писали, то в конкретном коде у вас можно найти с полдесятка ошибок.
И возможно даже тех, о которых вы знаете, но не исправляете smile


--------------------
user posted image
PM   Вверх
Pitlord
Дата 5.12.2009, 18:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 246
Регистрация: 31.10.2009

Репутация: 4
Всего: 7



Прямо-таки война концепций. Такую серьёзную проблему надо решать в разделе "PHP: Для профи", точно вам говорю.
PM MAIL   Вверх
Ипатьев
Дата 5.12.2009, 18:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2232
Регистрация: 5.7.2009

Репутация: 28
Всего: 37



Цитата(Simpliest @  5.12.2009,  12:06 Найти цитируемый пост)
А вообще это все глупости smile нужно использовать биндинг и не заниматься подстановкой в запросы. 

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

вернемся к вопросу.
Учитывая, что код в самом первом варианте практически не отличается от объявления массива, но при этом не требует дополнительной обработки, и является более гибким, стоит признать, что и "лапша" вполне имеет право на жизнь. 


PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "PHP"
Aliance
IZ@TOP
skyboy
SamDark
MoLeX

Новичкам:

  • PHP редакторы собираются и обсуждаются здесь
  • Электронные книги по PHP, документацию можно найти здесь
  • Интерпретатор PHP, полную документацию можно скачать на PHP.NET

Важно:

  • Не брезгуйте пользоваться тегами [code=php]КОД[/code] для повышения читабельности текста/кода.
  • Перед созданием новой темы воспользуйтесь поиском и загляните в FAQ
  • Действия модераторов можно обсудить здесь

Внимание:

  • Темы "ищу скрипт", "подскажите скрипт" и т.п. будут переноситься в форум "Web-технологии"
  • Темы с именами: "Срочно", "помогите", "не знаю как делать" будут УДАЛЯТЬСЯ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, IZ@TOP, skyboy, SamDark, MoLeX, awers.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1070 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.