Запрос MySQL с несколькими местами, некоторые из которых могут быть пустыми

#php #mysql #sql #database

#php #mysql #sql #База данных

Вопрос:

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

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

Как я могу это сделать? Большое спасибо за помощь!

@Ibu, это то, что у меня есть на данный момент:

 // Now we need to query the database for these terms
$sql_query = "SELECT * FROM `students` WHERE `first_name` = '" . $first_name . "' AND `last_name` = '" . $last_name . "' AND `nick_name` = '" . $nick_name . "' AND `grade` = '" . $grade . "' AND `gender` = '" . $gender . "'";
$result = mysql_query($sql_query);

// Let's check to make sure there is an actual result
$num_rows = mysql_num_rows($result);

if($num_rows < 1) {
    echo 'No student was found using that criteria.';
}

if($num_rows >= 1) {
    echo '<p>' . $num_rows . ' result(s) found. Below are the results:</p>';
    echo '<br />';
}

while($row = mysql_fetch_array($result)) {
    echo '
        <table border="1" width="400">
        <tr>
            <td colspan="2" align="center">Student Profile - ' . $row['last_name'] . ', ' . $row['first_name'] . '</td>
        </tr>
        <tr>
            <td>First Name: </td>
            <td>' . $row['first_name'] . '</td>
        </tr>
        <tr>
            <td>Last Name: </td>
            <td>' . $row['last_name'] . '</td>
        </tr>
        <tr>
            <td>Nick Name: </td>
            <td>' . $row['nick_name'] . '</td>
        </tr>
        <tr>
            <td>Grade: </td>
            <td>' . $row['grade'] . '</td>
        </tr>
        <tr>
            <td>Gender: </td>
            <td>' . $row['gender'] . '</td>
        </tr>
        </table> <br /><br />';

}
  

Комментарии:

1. покажите нам запрос, который у вас есть на данный момент

2. вы не получите никаких результатов с запросом, который у вас есть сейчас (если что-то осталось пустым)

3. @Neal, да, я знаю, вот почему я спрашиваю, что здесь делать 🙂

Ответ №1:

Эрланд Соммарског является фактическим источником по этому вопросу:
http://www.sommarskog.se/dyn-search-2005.html#conclusion

Я бы записал каждый параметризованный AND в формате, подобном этому:

 ...AND ((@Param IS NULL)  OR (@Param = your_column))
  

Комментарии:

1. Лучший выбор — хотя популярно создавать вместе какой-нибудь динамический оператор SQL, возможно, с «1 = 1», чтобы избежать необходимости решать, куда вставлять предложения «И». Это явно и полностью объявляет предполагаемый запрос.

2. @le dorfier однако это потенциально замедляет выполнение в зависимости от того, как настроена ваша СУБД. ссылка @Joe’s также отлично подходит для построения динамического SQL (который не будет кэшировать планы)

3. Существует также более лаконичная версия (@Param = your_column) IS NOT FALSE

4. @Andrew Lazarus но если @Param IS NULL тогда это приведет к нарушению равенства во всем … Я никогда не видел, чтобы это было написано так, как у вас там.

Ответ №2:

Вероятно, вы захотите создать SQL-запрос динамически. Прочитайте сообщение в блоге Гейл Шоу о универсальных запросах.

Комментарии:

1. 1 @Joe Забавно, что всякий раз, когда возникает повторный вопрос по этой теме, вы публикуете Гейл Шоу, а я публикую Эрланда Соммарскога (оба фантастические)

2. @Matthew PK: У всех нас есть свои любимые. 🙂 Согласитесь, что оба превосходны. Фактически, Гейл цитирует работу Эрланда в своем посте. Я думаю, что предпочитаю Gail, потому что он немного более лаконичный и ему легче следовать. Эрланд исчерпывающий, что иногда может быть утомительным.

3. и Эрланд не может побеспокоиться о реализации веб-макета.

Ответ №3:

Обычно я предпочитаю создавать «чистые» запросы, динамически создавая предложение WHERE. При условии, что вы должным образом очистили данные из $_POST и скопировали их в $data , а ключи в $data названы в честь полей, которые они будут использовать для фильтрации:

 $sql = "SELECT ..fields.. FROM ..table..";
$search_enabled_fields = array('firstname', 'lastname', 'email', /* ..etc.. */);
$conditions = array();
foreach ($search_enabled_fields as $field) {
  if (!empty($data[$field])) { // isset and not an empty string
    $value = $data[$field];
    // maybe you could sanitize $value here if you didn't before..
    $conditions[] = "$field = '$value'";
  }
}
if (count($conditions) > 0) {
  $sql .= " WHERE ". implode(' AND ', $conditions);
}
// now, execute your $sql query..
  

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

Ответ №4:

Просто проверьте $_POST переменные и создайте запрос на основе этого.

Например, так (это плохо тем, что не очищает $_POST для инъекции, но это хорошее начало):

 $whereSet = false;
$where = '';
if(isset($_POST['name'])){
    $whereSet = true;
    $where .= "WHERE name = '{$_POST['name']}'n";
}
if(isset($_POST['nick'])){
    if(!$whereSet){
        $where .= "WHERE ";
        $whereSet = true;
    }
    else {
        $where .= "AND ";
    }
    $where .= "nick = '{$_POST['nick']}'n";
}
//...etc
  

Затем просто добавьте $where переменную в конец вашего запроса

Комментарии:

1. это чрезвычайно подвержено sql-инъекции!

Ответ №5:

 $query = "select * from somewhere where 1 = 1";
if(isset($_POST['something'])){
  $query .= " and something = '{$_POST['something']}'";
}
if(isset($_POST['something_else'])){
  $query .= " and something_else = '{$_POST['something_else']}'";
}
  

и т.д., Но с экранированным вводом

значение 1 = 1 используется для того, чтобы не проверять, нужно ли добавлять ключевое слово «where»