Оператор поиска mySQL с несколькими фильтрами - PullRequest
1 голос
/ 10 марта 2012

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

Вот идет ...

Я пытаюсь создать поиск на моем веб-сайте списка адвокатов.

Table 1
ID (primary)
Name
Category1 (fkey)
Category2 (fkey) 
Category3 (fkey)
Category4 (fkey)
Category5 (fkey)
Location1 (fkey)
Location2 (fkey)
Location3 (fkey)
Location4 (fkey)
Location5 (fkey)

Table 2 - Locations
ID (primary)
Name 

Table 3 - Categories
ID (primary)
Name

Таким образом, у адвокатов есть несколько категорий и несколько местоположений -> отношение «один ко многим» как с таблицей 2, так и с таблицей 3

Первый вопрос: Правильно ли настроена таблица 1? Нужно ли иметь несколько столбцов местоположения и категории (например, location1, location2, location3 и т. Д.)? Или я усложняю это?

Далее ...

Я хочу поиск в стиле флажков на моем сайте. Пользователь может выполнять поиск по местоположению и / или по категории. И с флажком они могут выбрать несколько мест и / или категорий. Значения флажков - это идентификаторы местоположений и категорий (не имена)

Таким образом, это может происходить тремя способами.

  1. Поиск по местоположению ТОЛЬКО
  2. Поиск по категориям ТОЛЬКО
  3. Поиск по категориям в пределах местоположения

У меня две проблемы.

  1. Я могу заставить сценарии 1 и 2 работать, но только если установлен ОДИН флажок.
  2. Я понятия не имею, как вообще начать работать над сценарием 3.

Вот что у меня есть для сценария 1 & 2

$AttorneyLocation = $_POST['AttorneyLocation'];

for ($i="0"; $i<count($AttorneyLocation); $i++) {
    if (!is_numeric($AttorneyLocation[$i])) {
        $AttorneyLocation[$i]="";
    }
    if (empty($AttorneyLocation[$i])) {
        unset($AttorneyLocation[$i]);
    }
}

$AttorneyLocation = implode (" OR ", $AttorneyLocation);

$sqlCommand = "SELECT att_id, att_name, att_logo, att_addy, att_town, att_profile_url FROM attorneys WHERE att_location1='$AttorneyLocation' OR att_location2='$AttorneyLocation' OR att_location3='$AttorneyLocation' OR att_location4='$AttorneyLocation' OR att_location5='$AttorneyLocation'";

Опять же, это работает, но только при установленном флажке ОДИН, сбой при выборе двух или более. Похоже, что он ищет только установленный флажок ПОСЛЕДНИЙ, игнорируя те, что перед ним.

Для сценария 3 - Опять же, я просто не уверен, с чего начать, как мне объединить поиск категории в поиске местоположения?

Если кто-то может указать мне правильное направление, это было бы здорово, спасибо большое! Это моя первая попытка создать что-то подобное!

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

 <input type='checkbox' name='AttorneyCategory[]' value='$cat_id'> $category<br />
 <input type='checkbox' name='AttorneyLocation[]' value='$loc_id'> $location<br />

Ответы [ 3 ]

4 голосов
/ 10 марта 2012

Как указал @JonathanLeffler, ваша структура для Таблицы 1 - прекрасный пример того, чего не следует делать.Ваши поля Category * и Location * должны быть удалены из таблицы 1 и заменены двумя таблицами «многие ко многим» - attorney_locations (attorney_id, location_id) и attorney_categories (attorney_id, category_id).

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

Следующий раунд -

<?php

foreach ($_POST['AttorneyLocation'] AS $key => $val)    {
    if (is_numeric($val)) {
        $_POST['AttorneyLocation'][$key] = intval($val);
    } else {
        unset($_POST['AttorneyLocation'][$key]);
    }
}

$AttorneyLocations = implode (',', $_POST['AttorneyLocation']);

foreach ($_POST['AttorneyCategory'] AS $key => $val)    {
    if (is_numeric($val)) {
        $_POST['AttorneyCategory'][$key] = intval($val);
    } else {
        unset($_POST['AttorneyCategory'][$key]);
    }
}

$AttorneyCategories = implode (',', $_POST['AttorneyCategory']);

$sqlCommand = 'SELECT DISTINCT att_id, att_name, att_logo, att_addy, att_town, att_profile_url FROM attorneys ';

if ($AttorneyLocations) {
    $sqlCommand .= 'INNER JOIN attorney_locations ON attorneys.att_id = attorney_locations.attorney_id ';
}
if ($AttorneyCategories) {
    $sqlCommand .= 'INNER JOIN attorney_categories ON attorneys.att_id = attorney_categories.attorney_id ';
}

$sqlCommand .= 'WHERE 1=1 ';

if ($AttorneyLocations) {
    $sqlCommand .= "AND attorney_locations.location_id IN ($AttorneyLocations) ";
}
if ($AttorneyCategories) {
    $sqlCommand .= "AND attorney_categories.category_id IN ($AttorneyCategories)";
}
2 голосов
/ 10 марта 2012

Вы должны распечатать, что вы получаете от вашего implode():

$AttorneyLocation = implode (" OR ", $AttorneyLocation);

Это не будет действительный синтаксис SQL, потому что вам нужно прочитать что-то вроде:

location = 'location1' OR location = 'location2' OR ...

Итак, вы не генерируете действительный SQL, как вы наверняка увидите, напечатав SQL.

Ваш Table1 является катастрофой для отношений. Столбцы CategoryN или LocationN являются «запахами кода» SQL. Не ясно, что означает эта таблица; документирует ли это «И» или «ИЛИ» соединения между категориями и местоположениями, и категория 5 связана только с Местоположением5 или это также относится к Местоположению1? Не зная, что означают данные, мы не можем надежно предоставить правильный дизайн.


Учитывая, что каждый адвокат может практиковать до 5 категорий права, и может практиковать до 5 мест, тогда лучший дизайн для таблиц, вероятно, будет:

Attorney
ID           (pkey)
Name
...other details...

AttorneyCategory
AttorneyID   (fkey - references Attorney)
Category     (fkey - references Category)
(AttorneyID, Category) (pkey)

AttorneyLocation 
AttorneyID   (fkey - references Attorney)
Location     (fkey - references Location)
(AttorneyID, Category) (pkey)

На самом деле запрос будет также значительно проще, поскольку вам не нужно искать одно и то же имя местоположения в каждом из пяти различных столбцов или искать одну и ту же категорию в каждом из пяти различных столбцов.

0 голосов
/ 10 марта 2012

Ну, так как вы используете PHP, я просто рекомендую вам сделать оператор IF для каждого из фильтров, которые вы хотите, может быть, несколько, чтобы 2 или 3 фильтра работали вместе. ваша база данных настроена правильно, просто создайте PHP, если он с разными запросами, и он должен работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...