помогите сделать грамотный запрос

musicant

Новичок
помогите сделать грамотный запрос

Здравствуйте!

Есть форма с десятью селектами. (страны, курорты, отели, питание и т.д)
После сабмита идет запрос в MySQL - Select price FROM sometbl WHERE и вот тут в качестве условий перечисляются данные из селектов.

В некоторых селектах можно поставить значение по умолчанию "не имеет значения", но как в таком случае построить запрос в БД?

Например пользователь пропускает выбор питания, тип номера или количество ночей.
А они прописаны у меня в запросе и от них зависит итоговый результат:
WHERE Hotel_id='$hotel_id' AND nights='$nights' AND adults='$adults' AND children='$children' AND Board_id='$boarding' AND RoomCategory_id='$roomcat'

Подскажите путь решения.
 

baev

‹°°¬•
Команда форума
А в чём проблема-то?
Если «значение по умолчанию», значит условие не ставится — и всё.
 

musicant

Новичок
В том и проблема, что я не знаю как составить запрос к БД если заранее непонятно какие значения будут выбраны, а какие - нет.
 

Fortop

Новичок
musicant
Запрос собирать ручками в зависимости от того выбраны значения или нет.
Причем даже не столько сам запрос, сколько WHERE часть
 

musicant

Новичок
Fortop
понятно, что WHERE
непонятен сам процесс.

Не перебирать же все варианты через проверку каждой переменной
if(isset($_GET['roomcat'])!="") {
Select from...
}
и так для каждой переменной.
 

Fortop

Новичок
Мммм. Ну есть такая штука как
[m]array_intersect[/m]
и иже с ней

Собственно нужен массив ожидаемых значений.

И тогда делаем например вот так
PHP:
$list = array_intersect_key($allowed, $_GET/$_POST);
В $list у нас только разрешенные ключи.

В Вашем случае нужна немного другая функция из этого же набора, которая позволит отфильтровать и ключи и значения сразу.
 

musicant

Новичок
Fortop
с ходу array_intersect не понял, буду разбираться,
но как составить WHERE?
Ведь после каждого(кроме последнего) поля=>значения идет "AND"....
 

Fortop

Новичок
И пусть себе идет. Мы ему не мешаем
PHP:
$where = implode(' AND ', $conditionList);
 

Fortop

Новичок
Это разве не очевидно?

Только составьте $conditionList сначала правильно.
 

Fortop

Новичок
musicant
Мда.
Я надеюсь вы все же поняли что нужно конкатенировать строку с условиями к запросу.
И не забудете обработать входящие параметры с помощью [m]mysql_real_escape_string[/m] перед вставкой в запрос.

P.S. дабы избежать проблем, когда у Вас может не быть значений инициализируйте
PHP:
$conditionList = array(1);
Тогда даже если пользователь ничего не выберет у вас будет корректный запрос такого вида
[sql]SELECT * FROM tbl WHERE 1[/sql]
 

fixxxer

К.О.
Партнер клуба
Вот именно задолбавшись с такими ситуациями, я и начал использовать Blitz не по назначению =) то есть для построения sql-запросов.

Звучит странно, но это удобно очень:
PHP:
static private $SQL_SELECT_HOTELS = 
    "SELECT * FROM {{ t('Hotels') }}
     WHERE
     Hotel_id={{ i(hotel_id) }} 
     {{ IF nights }} AND nights={{ i(nights) }}{{ END }}
     {{ IF adults }} AND adults={{ i(adults) }}{{ END }}
     {{ IF children }} AND children={{ i(children) }}{{ END }}
     {{ IF boarding }} AND Board_id={{ i(boarding) }}{{ END }}
     {{ IF roomcat }} AND RoomCategory_id={{ i(roomcat) }}{{ END }}";

...

public function loadById($hotel_id, array $filter = array()) {
     $this->handleResult( $this->Db()->getAll(self::$SQL_SELECT_HOTELS, compact('hotel_id') + $filter) );
}
 

baev

‹°°¬•
Команда форума
fixxxer, а чем это:
PHP:
{{ IF nights }} AND nights={{ i(nights) }}{{ END }}
отличается от
Автор оригинала: musicant
Не перебирать же все варианты через проверку каждой переменной
if(isset($_GET['roomcat'])!="") {
?
 

fixxxer

К.О.
Партнер клуба
Тем, что вынесено в легко читаемый SQL-запрос.

Можно и так:

PHP:
static private $SQL_SELECT_HOTELS =  
    "SELECT * FROM {{ t('Hotels') }} 
     WHERE 
     Hotel_id={{ i(hotel_id) }}
     {{ BEGIN filter }}
        AND {{ field(name) }} = {{ s(value) }}
     {{ END }}";

... 

public function loadById($hotel_id, array $kwfilter = array()) {
    $filter = array();
    array_walk($kwfilter, function($k, $v) use (&$filter) { $filter[] = array('name' => $k, 'value' => $v); });
    $this->handleResult( $this->Db()->getAll(self::$SQL_SELECT_HOTELS, compact('hotel_id', 'filter')) ); 
}
Смотря что важнее - лаконичность или явность получаемого запроса.
 

musicant

Новичок
Сделал не слишком изящно, но вроде работает :)
Всем спасибо за помощь!


PHP:
$conditionList=array();
if($hotel_id !=""){
	$conditionList[]="Hotel_id='$hotel_id'";
}
if($nights!=""){
	$conditionList[]="nights='$nights'";
}
if($adults!=""){
	$conditionList[]="adults='$adults'";
}
if($children!=""){
	$conditionList[]="children='$children'";
}
if($boarding!=""){
	$conditionList[]="Board_id='$boarding'";
}
if($roomcat!=""){
	$conditionList[]="roomCategory_id='$roomcat'";
}
$where=implode(' AND ', $conditionList);
if(count($where>1)){
$res = db_query("SELECT Price FROM tbl WHERE $where");
while($row = mysql_fetch_assoc($res)) {
....
}}
if(count($where<=1)){
$res = db_query("SELECT Price FROM tbl");
while($row = mysql_fetch_assoc($res)) {
....
}}
 

Вурдалак

Продвинутый новичок
PHP:
$where_clause = empty($conditionList) ? '' : 'WHERE ' . implode(' AND ', $conditionList);
-~{}~ 18.02.10 02:47:

Кстати, а что в таком случае с индексами?
 
Сверху