Создание SQL-запроса с операторами OR на основе того, установлены ли флажки или нет - PullRequest
0 голосов
/ 16 января 2019

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

Пользователь может искать школы по всей стране по ряду параметров:

  • Тип школы (средняя школа, средняя школа, профессиональная школа, университет и т. Д.)
  • Статус школы (частная или государственная)
  • Город
  • Состояние
  • и т.д.

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

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

Таким образом, это подразумевает использование в моем поиске операторов OR, чтобы, например, у меня был SQL-запрос, подобный следующему:

SELECT schools.schoolId, schools.schoolName, villages.villageName FROM schools, villages
WHERE schools.villageId = villages.villageId

И здесь я бы поставил условие, чтобы по запросу возвращалась только информация, относящаяся к средним, средним и профессиональным школам:

AND (schools.schoolType = "MiddleSchool" OR schools.schoolType = "HighSchool" OR schools.schoolType = "TradeSchool")

Именно из-за конструкции этого утверждения у меня возникают проблемы.

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

Я использую PHP для генерации запроса на основе результатов формы.

Чтобы сгенерировать список всех доступных типов школ, я прочитал все существующие типы школ из базы данных (MySQL), используя запрос DISTINCT. Я использую это для составления списка всех доступных типов школ, которые я использую для создания формы поиска.

Поэтому я должен использовать аналогичный метод для сравнения результатов формы с базой данных. Это означает, что на моей странице результатов, чтобы увидеть, какие флажки были отмечены, мне нужно увидеть, какие флажки могли существовать в данный момент. форма была отправлена, поэтому я еще раз прочитал все доступные типы из базы данных: (некоторый код обрезан, это только тот запрос, который я использую, который, как я знаю, работает, но это только для контекста)

try 
{
    $pdo = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
    $req_sql_type_school = "SELECT DISTINCT schoolType AS types FROM schools";
    $res_type_schools = $pdo->query($req_sql_type_school);
    $res_type_schools->setFetchMode(PDO::FETCH_ASSOC);
} catch (PDOException $e) 
{
    die("Could not connect to the database $dbname :" . $e->getMessage());
}

После этого я перебираю результаты запроса, чтобы создать массив типов школ: (Я знаю, это тоже работает, но опять же, это только для контекста)

$arrayTypes = array();
while ($row = $res_type_schools->fetch())
{
    $arrayTypes[]=$row['types'];
}

Тогда вот где я борюсь. Именно в этот момент я должен создать оператор «И ...» в начале запроса, о котором я упоминал выше, который был:

SELECT schools.schoolId, schools.schoolName, villages.villageName FROM schools, villages
WHERE schools.villageId = villages.villageId

Чтобы увидеть, был ли пользователь помечен или нет, я перебираю массив, чтобы проверить, отмечен ли соответствующий флажок. Для этого вот код, который я написал. Примечание: basictext() просто форматирует строку в формат, который я использовал для значений моего флажка, то есть строки только в нижнем регистре без пробелов и без акцентов):

foreach($arrayTypes as $arr)
{
    if(isSet($_GET[basictext($arr)]))
    {
        echo "[x] Type ".$arr." <br/>";
    } 
    else 
    { 
        echo "[ ] Type ".$arr." <br/>"; 
    }
}

Это позволяет мне проверять, какие типы были проверены пользователем в форме поиска.

Однако я не знаю, как перевести это в оператор AND, который я хотел, а именно:

AND (schools.schoolType = "MiddleSchool" OR schools.schoolType = "HighSchool" OR schools.schoolType = "TradeSchool")

Я думал о том, чтобы поместить каждый тип в круглые скобки и отделить каждый тип с помощью OR, и писать только в круглых скобках, если тип действительно проверен.

Это привело к чему-то вроде этого:

AND ((schools.schoolType = 'MiddleSchool') OR () OR () OR (schools.schoolType = 'HighSchool') OR () OR () OR ())

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

Одно из решений, о которых я подумал при написании этого, - поместить каждый «действительный» тип в массив, а затем использовать этот массив, длину которого я бы тогда знал. Тогда я смогу создать ожидаемый оператор AND, потому что тогда у меня будет определенное количество отмеченных флажков, и это также позволит мне полностью игнорировать не отмеченные значения. Как вы думаете, это будет работать?

Ответы [ 2 ]

0 голосов
/ 16 января 2019

Если ваш столбец schools.schoolType имеет произвольный тип данных VARCHAR, должна существовать некоторая связь между данными, которые пользователь отправляет, и данными, используемыми в запросе, если только вы заранее не определили список возможных значений.

Похоже, у вас есть какая-то связь между вашим массивом arrayTypes и значением $_GET.Поэтому, если запрос требует HighSchool, это может быть обнаружено, если пользователь отправляет highschool, используя вашу функцию basictext().

Оттуда я бы сделал что-то вроде этого:

$selectedTypes = array();

foreach($arrayTypes as $arr)
{
    if(isSet($_GET[basictext($arr)]))
    {
        echo "[x] Type ".$arr." <br/>";
        $selectedTypes[] = $arr;
    } 
    else 
    { 
        echo "[ ] Type ".$arr." <br/>"; 
    }
}

Это заполнит массив selectedTypes соответствующими типами того, что отправляет пользователь.

При использовании этого звучит так, будто вы хотите добавить предложение IN к вашему окончательному запросу.

$placeholders = implode(',', array_fill(0, count($selectedTypes), '?'));

$template = "SELECT schools.schoolId, 
                    schools.schoolName, 
                    villages.villageName 
               FROM schools, 
                    villages
              WHERE schools.villageId = villages.villageId
                AND schools.schoolType IN ($placeholders)";

$stmt = $pdo->prepare($template);
$stmt->execute($selectedTypes);
$result = $stmt->fetchAll();
$stmt = null;

Если selectedTypes содержит ["HighSchool", "MiddleSchool", "TradeSchool"], то $placeholders будет содержать [?, ?, ?].Это используется для создания шаблона SQL для подготовленного запроса оператора с использованием массива selectedTypes в качестве входных данных.

$result должны иметь данные, которые вы ищете.

0 голосов
/ 16 января 2019

Так что, если я вас правильно понимаю, вам просто нужно написать что-то, чтобы объединить фрагменты оператора OR на основе битового массива. Вместо добавления ИЛИ для каждой записи, независимо от того, отмечена она или нет, выполните что-то вроде

    first = true
    string orClause = ""
    array schoolTypes
    array checkedSchoolTypes

    for(i = 0; i < checkedSchoolTypes.length; i++)
        if(first && checkedSchoolTypes[i])
           orClause += "schools.schoolType = " + schoolTypes[i]
           first = false
        else if(checkedSchoolTypes[i])
             orClause += "OR schools.schoolType = " + schoolTypes[i]

   query = "This is your query" + orClause + "rest of your query"

* Обратите внимание, что это решение для школьного проекта, а не производственной среды. Если бы вы делали это в производственной среде, в этом случае вы бы хотели передать информацию через параметризованную хранимую процедуру и сгенерировать свое заявление в sql на основе информации, переданной из формы.

Вместо того, чтобы делать или, как вы предлагаете, вы могли бы сделать, и оператор IN, как и другие, предполагают, что код будет в основном таким же с другим форматом. Дайте мне знать, если вам нужны какие-либо разъяснения.

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