Поиск по БД с использованием большого количества полей

FireMaster

Guest
Поиск по БД с использованием большого количества полей

Здравствуйте, обитатели PHP Club`a, вот сравнительно недавно стал читать Ваш портал, за помощью никогда не обращался, так как всегда либо находил ответ на свой вопрос здесь, либо в комментариях на php.net, либо просто все получалось методом тыка :) Вот так методом проб и ошибок учу PHP... Но сейчас реально появилась нобходимость попросить помощи, возможно это уже где-то обсуждалось, я такой вариант не исключаю, но, как мне кажется, я просмотрел все темы форумов и перебрал всевозможные варианты ключевых слов и словосочетаний в функции поиска, поэтому если что-то похожее где-то было, ткните меня носом в эту тему, буду рад почитать. Надеюсь после такого длинного вступления кто-то еще читает этот пост :rolleyes: , итак собственно вопрос: необходимо написать скрипт на PHP, который осуществляет поиск по базе данных MySQL. Но не все так просто, в качестве формы будет выступать форма в которой будет от 10 до 15 полей, в которые, соответственно, может быть введен или не введен параметр, надеюсь, что все кто это читают, поняли что я имею ввиду. Итак, имеются 2 файла: search.php и functions.php (поиск по БД это последняя часть небольшого интерфейса администратора над которым я работаю, все остальное я уже сделал). Теперь собственно сам код, все содержимое я приводить не буду, т.к. это бессмысленно, опишу лишь общие моменты. Итак, файл search.php: он разделен на 2 режима, первый это
PHP:
if($_GET['mode'] == "search" || !isset($_GET['mode']))
здесь я думаю все понятно, далее идут форма и собственно само условие поиска и переменные:
PHP:
 if($_POST['search_candidat']) {
   $surname = $_POST['surname'];
   $name = $_POST['name'];
   $otchestvo = $_POST['otchestvo'];
   $otdel = $_POST['otdel'];
   $vacancy = $_POST['vacancy'];
   $resultat = $_POST['resultat'];
   $result = $admin->search_candidates_in_profile($surname, $name, $otchestvo, $otdel, $vacancy, $resultat);
	}
здесь также все элементарно, берем введенные пользователем переменные и передаем их в functions.php функции search_candidates_in_profile. Вот содержимое этой функции:
PHP:
function search_candidates_in_profile($surname, $name, $otchestvo, $otdel, $vacancy, $resultat) {
	global $db_profile,$object;
	$query = "SELECT * FROM $db_profile WHERE uid !=0";
	if ($surname !="") {
		$query .= " AND surname = '$surname'";
	}
	else
		$query .= "";
	if ($name !="") {
		$query .= " AND name = '$name'";
	}
	else
		$query .= "";
	if ($otchestvo !="") {
		$query .= " AND otchestvo = '$otchestvo'";
	}
	else
		$query .= "";
	if ($otdel !="") {
		$query .= " AND otdel = '$otdel'";
	}
	else
		$query .= "";
	if ($vacancy !="") {
		$query .= " AND vacancy = '$vacancy'";
	}
	else
		$query .= "";
	if ($resultat !="") {
		$query .= " AND resultat = '$resultat'";
	}
	else
	$query .= "";
		$query .= " ORDER BY uid";
	$result = $this->db->db_query($query);
	if (mysql_num_rows($result) == 0) {
		header ('Location: handlings.php?mode=noMatches');
	}
	else
		$num_fields = mysql_num_fields($result);
		$j=0;
		$x=1;
		while ($row = $this->db->db_fetch_array($result)) {
			for($j=0;$j<$num_fields;$j++) {
					$name = mysql_field_name($result, $j);
				$object[$x][$name] = $row[$name];
			} $x++;
		}
		mysql_free_result($result);
		header ('Location: search.php?mode=result');
	}
здесь я думаю также все понятно, поэтому комментировать ничего не буду, знающие люди все поймут сами. И наконец привожу код второго режима файла search.php:
PHP:
elseif ($_GET['mode'] == "result") {

$admin->search_candidates_in_profile($surname, $name, $otchestvo, $otdel, $vacancy, $resultat);

	}

$i=1;
$ii=count($object);
Здесь по моей задумке вызывается функция и обсчитываются результаты при помощи цикла:
PHP:
for($i=1;$i<=$ii;$i++) {
здесь html тэги через которые выводится результат
}
Но, ничего не работает, иначе я бы не стал постить это сообщение, реакция скрипта такова, что после введения значений в форму поиска, скрипт начинает выполняться, но никогда не останавливается, т.е. такое впечатление что создается бесконечный цикл, который никогда не закончится. Данные в функцию передаются, естественно, без проблем, проблема в том, как их вытащить (я думаю здест моя проблема), мои предположения таковы, что у меня кривые руки :D и я что-то где-то не там разместил) да и еще вопрос, при редиректе на search.php?mode=result переменные теряются или нет ? Если теряются, то как сделать, чтобы не терялись ? Через сессию или есть еще варианты ? Мучаюсь уже третий день, перепробовал уйму вариантов... Если кто-то дочитал до конца это сообщение, то наверное Вам можно дать медаль за терпение :D Надеюсь на скорый ответ, с уважением FireMaster.
 

Кром

Новичок
Вот это очень сомнительная проверка:
if($_GET['mode'] == "search" || !isset($_GET['mode']))

Эти строки лишние:
else $query .= "";

> при редиректе на search.php?mode=result переменные теряются или нет ?

Теряются. Для начала оставь редирект в покое и выведи данные на той-же странице. Проверь все ли работает. Потом положи все в сессию и тогда уже думай о редиректе.
Не забудь прочитать faq.phpclub.net там есть описание работы сессий и проблем возникающих при редиректе.
 

nuto

Guest
теряются результаты вашего запроса, и "во втором режиме" файла search.php вы засовываете в search_candidates_in_profile() пустоту
соответственно в functions.php работает [SELECT * FROM $db_profile WHERE uid !=0], т. е. выбрать всё, а поскольку снова mysql_num_rows($result)>0, то натыкаетесь опять на Location: search.php?mode=result и отправляясь туда же, откуда пришли, и снова с пустыми руками
и т. д. по кругу со всеми остановками
пользуйтесь главной мыслью Крома => меняйте структуру

update: да, забыл
теряeтся конечно не только (корректный в первом проходе, кстати) массив слитый в $object, но и весь $_POST естественно, и глобали тут не помошники, т. к. вы перегружаетесь по любому
 

nuto

Guest
...и вместо копирования массива $_POST в переменные в самом начале и эпопеи if/else в текущей реализации, продолжаайте работать с ним (массивом) и далее, предварительно, конечно, проверив и отформатировав (он у вас уже есть, так зачем его убивать?)
это на порядок сократит и сделает более удобочитаемым ваш код, для себя же прежде всего
 

FireMaster

Guest
Большое спасибо вам всем за ответы, дело было именно в редиректе, т.е. переменные не передавались, как только я его убрал все отлично заработало. Сейчас буду думать с сессией, только есть вопрос, стоит ли делать именно через сессию ? Может создавать временную таблицу и пихать результаты запроса туда, а потом оттуда делать select ? Или это я сейчас полный бред написал :confused:

и ещё, нужно писать не
if($variable!="")
a:
if(!empty($variable))
Почему ? Так грамотней ?

Эти строки лишние:
else $query .= "";
Возможно, но мне так понятней, что там происходит...

...и вместо копирования массива $_POST в переменные в самом начале и эпопеи if/else в текущей реализации, продолжаайте работать с ним (массивом) и далее, предварительно, конечно, проверив и отформатировав (он у вас уже есть, так зачем его убивать?)
Опять же, мне с переменными более понятно работать, я пока только учусь, возможно в будущем, как поднаберусь опыта буду придерживаться Вашей точки зрения.

Да и еще, если делаеся выборка из нескольких таблиц, что надо использовать UNION или LEFT/JOIN ? Поскольку синтаксис этих команд мне не совсем понятен из мануала, сли кому не сложно объясните. Спасибо.
 

Falc

Новичок
Originally posted by FireMaster
Да и еще, если делаеся выборка из нескольких таблиц, что надо использовать UNION или LEFT/JOIN ? Поскольку синтаксис этих команд мне не совсем понятен из мануала, сли кому не сложно объясните. Спасибо.
Забудь пока про UNION - это операция, которая поддерживаеться начиная только с 4-ой версии и бывает нужна крайне редко.
В то время как JOIN присутствует в 90% выборок.
Так что читай ман на JOIN:
http://www.mysql.com/doc/ru/JOIN.html
 

FireMaster

Guest
Прочитал в очередной раз... Ну не понимаю я синтаксиса (по крайней мере для моего конкретного случая), пробовал
SELECT * FROM $db_profile LEFT JOIN $db_dates ON $db_profile_uid = $db_dates_uid WHERE uid !=0 AND bla = $bla и т.д. (дальше пошли if else) ORDER BY uid
и вот так
SELECT * FROM $db_profile LEFT JOIN $db_dates USING uid WHERE uid !=0 AND bla = $bla и т.д. (дальше пошли if else) ORDER BY uid
и еще как-то, все время мускул матерится как сапожник на синтаксис моего запроса... помогите, пожалуйста, с правильным синтаксисом. Спасибо.
 

FireMaster

Guest
Нет ну я это все читал (уже раз 10)... но все равно не понимаю как сделать SELECT из двух и более таблиц...

Вот как я пишу:
PHP:
$query = "SELECT * FROM $db_profile LEFT JOIN $db_dates ON $db_profile.uid=$db_dates.uid WHERE uid !=0 AND surname = '$surname' AND ......... ORDER BY uid";
В ответ на это получаю:
Column: 'uid' in where clause is ambiguous
Warning: mysql_num_fields(): supplied argument is not a valid MySQL result resource in /var/www/test/functions.php on line 292

Warning: mysql_free_result(): supplied argument is not a valid MySQL result resource in /var/www/test/functions.php on line 301
Column: 'uid' in where clause is ambiguous
Warning: mysql_num_fields(): supplied argument is not a valid MySQL result resource in /var/www/test/functions.php on line 292

Warning: mysql_free_result(): supplied argument is not a valid MySQL result resource in /var/www/test/functions.php on line 301

Cодержимое строк 292-301:
PHP:
292: $num_fields = mysql_num_fields($result);
293: $j=0;
294: $x=1;
295: while ($row = $this->db->db_fetch_array($result)) {
296: for($j=0;$j<$num_fields;$j++) {
297: $name = mysql_field_name($result, $j);
298: $object[$x][$name] = $row[$name];
299: } $x++;
300:}
301: mysql_free_result($result);
Ну объясните мне, очень прошу, объясните что я делаю не так, вроде синтаксис по ману и все равно не работает :-(
 

Falc

Новичок
Originally posted by FireMaster
В ответ на это получаю:
Column: 'uid' in where clause is ambiguous
У тебя поле uid присутствует в обоих таблицах MYSQL не знает которое из них сравнивать с нулем
Если делаешь выборку из нескольких таблиц, то лучше у всех полей указывать имя таблиц
 

FireMaster

Guest
Большое спасибо, Falc, теперь все работает, правда я написал запрос без LEFT JOIN, вот как у меня получилось:
PHP:
SELECT $db_one.*, $db_two.*, $db_three.*, $db_four.* FROM $db_one, $db_two, $db_three, $db_four WHERE $db_two.uid = $db_one.uid AND $db_three.uid = $db_one.uid AND $db_four.uid = $db_one.uid ORDER BY $db_one.uid DESC
И появился очередной вопрос... в таблице $db_three имеется 7 полей: uid,tableA1,tableB1,tableA2,tableB2,tableA3,tableB3 но в форме поиска надо обобщить все tableA под одним полем и все tableB под другим полем, т.е. в запросе должно быть что-то типа
AND tableA1,tableA2,tableA3 = '$tableA'
AND tableB1,tableB2,tableB3 = '$tableB'
но ведь так не пишется, это же не правильно, вопрос в том как правильно.
 

Falc

Новичок
2FireMaster:
Во-первых зачем ты используешь в качестве названий таблиц переменные?
Этого по возможности лучше избегать.

По этому в твоем запросе крайне тяжело разобраться.

А твой вопрос я вообще не понял :)
 

FireMaster

Guest
Переменные использую потому, что админ базы любит менять названия таблиц, вот чтобы мне каждый раз все файлы не перелопачивать, я и использую переменные. Мне в запросе разобратья легко, наверное потому что я его писал :) Насчет моего вопроса... сейчас попробую объяснить по другому:

Возьму как пример следующее:
есть таблица в которой имеем поле uid (ну это я думаю ясно), а также 3 поля с последними местами работы, т.е. work1 (последнее местол работы), work2 (предоследнее место работы) и work3 (предпредпоследнее место работы :) ) то же самое и с должностями, т.е. position1 (должность на последнем месте работы, position2 (дожность на предпоследнем месте работы) и position3 (должность на предпредпоследнем месте работы), уфф... так вот, теперь у нас имеется форма поиска, а в ней имеется всего 2 поля: Место работы и должность, вопрос: как составить запрос таким образом чтобы при указании в этих двух полях Места работы и(или) Должности мускул выводил результаты из всех трех таблиц, т.е. если человек когда то работал на предприятии Рога и Копыта и у нас в базе эта инфа есть либо в последнем месте работы, либо в предпоследнем месте работы, либо в предпредпослденем месте работы то полюбому этот человек бы выводился. уфф =) надеюсь я тебя не запутал =)
 

chira

Новичок
Если не поздно , лучше поменять структуру:
Создать таблицу
[SQL]CREATE TABLE WORK_PLACES (id int auto_increment, uid int, work varchar(100), position varchar(100), work_from date, work_to date);[/SQL]
Эта таблица будет связана с таблицей $db_profile по полю uid.
Запрос будет выглядеть так:
[SQL]SELECT DISTINCT a.* FROM $db_profile a, WORK_PLACES wp WHERE a.uid=wp.uid;[/SQL]
 

FireMaster

Guest
Так это и так отдельная таблица, т.е. все записи о последних трех предыдущих работах и должностях на них лежат в отдельной табличке, проблема в том, чтобы вот в этот запрос
PHP:
SELECT $db_one.*, $db_two.*, $db_three.*, $db_four.* FROM $db_one, $db_two, $db_three, $db_four WHERE $db_two.uid = $db_one.uid AND $db_three.uid = $db_one.uid AND $db_four.uid = $db_one.uid ORDER BY $db_one.uid DESC
который замечательно осуществляет поиск по БД, добавить еще и решение для ситуации которую я описал.
 

chira

Новичок
напиши так:
... AND (tableA1 = '$tableA' OR tableA2 = '$tableA' OR tableA3 = '$tableA')
 

FireMaster

Guest
Автор оригинала: chira
напиши так:
... AND (tableA1 = '$tableA' OR tableA2 = '$tableA' OR tableA3 = '$tableA')
Просто супер, chira, большое Вам спасибо, Вы меня очень выручили.
 
Сверху