Поиск (фильтр) по нескольким значениям и проблем с AND запросе.

Статус
В этой теме нельзя размещать новые ответы.

Руслан

Новичок
Поиск (фильтр) по нескольким значениям и проблем с AND запросе.

Робятки выручайте.
Не доеду как сделать поиск по нескольким значениям (составить запрос) которые приходят из формы.
Делаю следующим образом -

PHP:
if (isset($nz) or isset($fday_day) or isset($fday_month) or isset($fday_year) or isset($fobject) or isset($fnik) 
    or isset($fnuch) or isset($fznak) or isset($fspec) or isset($fstatus) or isset($fakt))  {
  if ($nz=="" and $fday_day=="" and $fday_month=="" and $fday_year=="" and $fobject=="" and $fnik=="" 
      and $fnuch=="" and $fznak=="" and $fspec=="" and $fstatus=="" and $fakt=="")     {
      $where="";
   } else {
      $where="where";
   }
}  else   {
  $where="where";
}

if(isset($fstatus)) {
    if($fstatus!=""){
      $pstatus="status=".$fstatus;
    }else{
      $pstatus="";
    }
} else {$pstatus='status!="завершенна"';}

if(isset($nz) and $nz!="") {$pnz="id=".$nz;}
if(isset($fobject) and $fobject!="") {$pfobject="id=".$nz;}
$zayavkaq = mysql_query("SELECT * FROM zayavka ".$where." ".$pstatus." ".$pnz."");
Там есть особенности, поэтому в кратце объясню
Принимаю значения они с буквой f впереди, проверяю есть ли они, если есть проверяю все ли они пустые - если все пустые то вываливается весь список поэтому $where - пустой.
Если не все пустые то where нужен для запроса. Если их вобще нет ( при первом заходе на страницу) то where нужен что бы вывести только те у которых статус "незавершенна".
Вобщем с were у меня всё получилось.. Думал по аналогии сделать с AND в запросе - т.е при проверке значений увеличивать дополнительную переменную на 1. и если переменая > чем 1, то вводить AND.

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

$pstatus="AND status=".$fstatus; Но как узнать что она пойдет первой что бы не получилось where and AND status="новая" допустим?Можно конечно по порядку смотреть не пустое ли предыдущее значение, но мне кажется что так получится несколько громоздко..

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

cDLEON

Онанист РНРСlub
1) Учитесь работать с массивами [m]array[/m]
2) Учитесь работать с суперглобальными массивами [m]tutorial.forms[/m]
3) Учитесь работать с циклами [m]for[/m] [m]foreach[/m] [m]while[/m]
4) Так же почитайте интерисующие вас темы здесь http://phpclub.ru/detail/
 

baev

‹°°¬•
Команда форума
Код:
WHERE 1=1 ....
— дальше любой параметр будет с 'AND'
 

С.

Продвинутый новичок
PHP:
$cond = array();
if ($var1) $cond[] = "field1='$var1'";
if ($var2) $cond[] = "field2='$var2'";
if ($var3) $cond[] = "field3='$var3'";
...
$cond = implode(' AND ',$cond);
 

Фанат

oncle terrible
Команда форума
Руслан
Слушай, как ты свой код-то вообще читаешь?
Я, пока не выровнял, ничего понять в нем не мог совершенно
 

Руслан

Новичок
cDLEON
Про массивы подумал когда домой уже приехал..
Действительно это позволит сразу вычислить кол-во переменных пришедших непустыми и организовать цикл для запроса.


baev
Эта мысль мне приходила в процессе написания, но без использования массива там всё равно как мне показалось имеются некоторые сложности.. Скорей всего я это использую в совокупности с массивами.

Ф а н а т
Да, с этим у меня наверно есть некоторые сложности, н сам читаю в лёт.. Эо наврно как человек у которого плохой почерк без труда читает свои каракули. Если мой почерк принес кому либо неудобства - мужики, примите мои извинения и благодарность за то что не бросаете в трудную минуту =))

-~{}~ 14.01.08 15:52:

И всем вопрос на вскидку.. сейчас начнете посылать в мануалы.. Тем не менее вопрос - работа с суперглобальной переменной (массивом) POST осуществляется как с обычными массивами или есть различия? Я почему спрашиваю.. Нужно ли мне формировать другой массив из формы или пользоваться суперглобальным?
 

Руслан

Новичок
Пробую.. Есть вот такая штука array_count_values - она возвращает кол-во всех значений по значениям.. А нет ли такой функции что то типа array_count_values ($array, 'тест') что бы она возвратила именно кол-во значений "тест" в массиве? Что бы не надо было их через цикл проверять и считать.
 

FractalizeR

Новичок
Автор оригинала: Руслан
Пробую.. Есть вот такая штука array_count_values - она возвращает кол-во всех значений по значениям.. А нет ли такой функции что то типа array_count_values ($array, 'тест') что бы она возвратила именно кол-во значений "тест" в массиве? Что бы не надо было их через цикл проверять и считать.
PHP:
count(array_keys($myArray, $mySearchValue))
- можно так сделать. array_keys позволяет возвращать только часть ключей.
 

Руслан

Новичок
Хотел вот так сделать
$a=array_count_values ($_POST, '')
$b=count ($_POST)
$c=$b-$a
и потом цикл $c раз
А так сделал через проверку пустой или не пустой..
 

dimagolov

Новичок
Руслан, ну цикл $c раз, а как ты будешь вынимать из массива именно непустые значения?
 

FractalizeR

Новичок
Несколько раз вопрос прочитал, но не могу сказать, что полностью понял, в чем он состоит :) Похоже, что речь идет об удобной подстановке параметров, переданных из формы через $_GET или $_POST в запрос с проверкой на корректность и танцами с бубном. Попробую предложить свое решение. Его можно будет модифицировать под конкретную задачу.

Param.class.php
PHP:
<?php

class Fractal_URL2QueryHelper_Param {
	const ARRAY_NAME_GET = 1;
	const ARRAY_NAME_POST = 2;
	private $_paramValue;
	private $_stringForSQL;

	function __construct($arrayName, $paramName, $defaultParamValue, $paramFormatString, array $param2SQLMap, $enforceType) {
		
		$valueSet = (($arrayName == self::ARRAY_NAME_GET) ? isset($_GET [$paramName]) : isset(
			$_POST [$paramName]));
		//Calculating value
		if ($valueSet) {
			$this->_paramValue = (($arrayName == self::ARRAY_NAME_GET) ? $_GET [$paramName] : $_POST [$paramName]);
		} else {
			$this->_paramValue = $defaultParamValue;
		}

		//Checking magic values and forming SQL string
		if (in_array($this->_paramValue, array_keys($param2SQLMap))) {
			$this->_stringForSQL = $param2SQLMap [$this->_paramValue];
		} else {
	              	//Enforcing type
			if ($enforceType) {
				settype($this->_paramValue, $enforceType);
			}
			$this->_stringForSQL = sprintf($paramFormatString, 
				mysql_real_escape_string($this->_paramValue));
		}
	}

	function getValue() {
		return $this->_paramValue;
	}

	function getStringForSQL() {
		return $this->_stringForSQL;
	}
}
?>

Как это работает:
PHP:
//В начале скрипта создаем объект параметра
$loginParameter = new Fractal_URL2QueryHelper_Param(
	Fractal_URL2QueryHelper_Param::ARRAY_NAME_GET, //- указываем, что параметр получаем из $_GET
        'login', - //указываем, что поле формы (ну или URL параметр) называлось login - $_GET['login']
        '%', // - значение параметра login по умолчанию, если в $_GET его не оказалось
        'user_login LIKE "%s"', //Строка форматирования для подстановки в WHERE условие запроса
	array ('%' => '1' ), //Массив для преобразования параметров по умолчанию в значения для 
                                     //подстановки в запрос. Т.е. если $_GET['login'] == '%', тогда в WHERE 
                                     //подставится единица, т.е. "истина", что равносильно отсутствию условия
        "string" //Указываем, что через $_GET['login'] нам должны передать значение строкового типа
);

//При выводе в HTML используем getValue();
$loginParameter->getValue() // вернет значение параметра для подстановки в HTML. Скажем,
echo('<INPUT id="test" name="test" value="'.htmlentities($loginParameter->getValue()).'">');

$TemplateEngine->assign('Login', $loginParameter->getValue());   //или так (я пользуюсь шаблонным движком)

//При подстановке в запрос используем getStringForSQL()
$loginParameter->getStringForSQL() //вернет значение для подстановки в WHERE запроса
$sql = 'SELECT * FROM fr_users WHERE ' . $loginParameter->getStringForSQL();
//Или так, если параметров много:
$UsersRS = array ( );
if (isset($_GET ['action'])) {
	$SQLParameters = array ($loginParameter->getStringForSQL(), $roleParameter->getStringForSQL(), 
		$emailParameter->getStringForSQL(), $accountStatusParameter->getStringForSQL(), 
		$countryParameter->getStringForSQL() );
	$SQLWhere = implode(' AND ', $SQLParameters);
	
	$sql = 'SELECT * FROM fr_users WHERE ' . $SQLWhere;
	$UsersRS = $DBConnection->select($sql);
}
$TemplateEngine->assign('UserList', $UsersRS);
Класс написан только вчера для внутреннего пользования, поэтому кое-что может выглядить нелепо :)
 

Фанат

oncle terrible
Команда форума
Кстати, что аффтар, что С. напрочь забыли о безопасности

-~{}~ 15.01.08 16:27:

FractalizeR
не пробовал сократить свое решение раз в 10?
 

FractalizeR

Новичок
Автор оригинала: *****
С. уже посоветовал.
Действительно. Но С. привел только схему решения проблемы. Я не думаю, что если это использовать в реальном скрипте, это будет выглядеть также компактно. За исключением моментов, наверное, когда только админ имеет доступ к какой-то странице.
Нужно ведь еще, скажем, settype($_GET['id'], 'integer') использовать для числовых значений. Для передачи параметров, описывающих сложное условие, придется использовать switch (типа "Все заказы" => "1", "Только мои заказы" => "userid=$userid", "Только открытые заказы"=> "orderstate='opened'"...)
 

Фанат

oncle terrible
Команда форума
"Только открытые заказы" - это не кейс рядом с мои заказы.
а иф , прараллельный им.
и прекрасно уклыадвается в схему.

груз твоих знаний очень сильно на тебя давит, на мой взгляд
 

FractalizeR

Новичок
Автор оригинала: *****
"Только открытые заказы" - это не кейс рядом с мои заказы.
а иф , прараллельный им.
и прекрасно уклыадвается в схему.

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

Что касается "заказов" - пример был упрощен, но я думаю, суть была понятна.

Так или иначе, я просто предложил :) Мне самому удобнее, когда логика сосредоточена во внешнем классе, а не в текущем коде.
 
Статус
В этой теме нельзя размещать новые ответы.
Сверху