Построение длинного запроса и много операторов if - есть ли более элегантный способ? - PullRequest
7 голосов
/ 12 августа 2010

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

    $sql = "SELECT DISTINCT fkRespondentID FROM tblRespondentDayTime";

    if (!empty($day) || !empty($time) || !empty($sportID)) {

        $sql .= " WHERE";

        if (!empty($day)) {
            $sql .= " fldDay='$day'";
        }

        if (!empty($time)) {
            if (!empty($day)) {
                $sql .= " AND";
            }
            $sql .= " fldTime='$time'";
        }

        if (!empty($sportID)) {
            if (!empty($day) || !empty($time)) {
                $sql .= " AND";
            }
            $sql .= " fkRespondentID IN (SELECT fkRespondentID FROM tblRespondentSport WHERE fkSportID='$sportID')";
        }

    }

Ответы [ 8 ]

6 голосов
/ 12 августа 2010

Я бы использовал старый "WHERE 1=1" трюк;добавьте это как первое условие, а затем вы можете принять условие «И» для каждого следующего оператора.

4 голосов
/ 13 августа 2010
$sql = "SELECT DISTINCT fkRespondentID FROM tblRespondentDayTime WHERE 1=1";

if (!empty($day))
    $sql .= "AND fldDay='$day'";

if (!empty($time)) {
    $sql .= "AND fldTime='$time'";

if (!empty($sportID))
    $sql .= "AND fkRespondentID IN (SELECT fkRespondentID FROM tblRespondentSport WHERE fkSportID='$sportID')";
1 голос
/ 13 августа 2010

Вместо того, чтобы делать проверки типа if (!empty($day) || !empty($time)), вы можете создать переменную $whereClause и проверить ее следующим образом:

$sql = "SELECT DISTINCT fkRespondentID 
        FROM tblRespondentDayTime";

$whereClause = '';

// fldDay
if (!empty($day)) {
    $whereClause .= " fldDay='$day'";
}

// fldTime
if (!empty($time)) {
    if (!empty($whereClause)) {
        $whereClause .= ' AND ';
    }
    $whereClause .= " fldTime='$time'";
}

// fkRespondentID
if (!empty($sportID)) {
    if (!empty($whereClause)) {
        $whereClause .= ' AND ';
    }
    $whereClause .= " fkRespondentID IN (SELECT fkRespondentID 
                                         FROM tblRespondentSport 
                                         WHERE fkSportID='$sportID')";
}

if (!empty($whereClause)) {
    $whereClause = ' WHERE '.$whereClause;
}

$sql .= $whereClause;

Это также будет работать, если вам нужно, скажем, изменить некоторые на OR (трюк 1 = 1 в этом случае не сработает и даже может оказаться весьма опасным).

1 голос
/ 12 августа 2010

Создает список / массив условий, где каждое условие является необязательным (т. Е. Если условие допустимо, нажмите его в списке).

Если этот список> 0, добавьте «где», а затем добавьте список, объединенный «и».

0 голосов
/ 13 августа 2010

Если вы используете хранимые процедуры, вы можете сделать что-то вроде этого:

CREATE PROCEDURE `FindRespondents` (
    IN `_day` varchar(255),
    ...
)
BEGIN
    SELECT DISTINCT fkRespondentID 
    FROM tblRespondentDayTime
    WHERE (_day Is Null OR fldDay = _day)
        AND ...
END;
|

Передача null для _day означает, что любой fldDay в порядке.Любое другое значение для _day, и оно должно совпадать.Я предположил, что fldDay - это текст, но, конечно, вы можете здесь все правильно ввести.

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

0 голосов
/ 12 августа 2010

К сожалению, создание динамического SQL - утомительный опыт, и даже если вы можете изменить некоторые вещи в своей логике (которая на самом деле выглядит относительно чистой), она все равно будет уродливой.

К счастью, Объектно-реляционное отображение существует. Я не слишком знаком с PHP, но в Perl есть несколько модулей CPAN, таких как SQL :: Abstract, которые позволят вам создавать довольно сложные операторы SQL с использованием базовых структур данных.

0 голосов
/ 12 августа 2010

Вот мое решение:

$sql = "SELECT * FROM table";
$conditions = array(
  'fldDay' => $day,
  'fldTime' => $time,
);

if (count(array_filter($conditions))) {
  $sql .= ' WHERE ';
  $sql .= implode(' AND ', array_map(function($field, $value) {
    return $field . '=\'' . pg_escape_string($value) . '\'';
  }, array_keys($conditions), $conditions));
}

Обратите внимание, что из-за замыканий это не будет работать ниже PHP 5.3. Если вы используете более старый PHP, сделайте замыкание отдельной функцией или замените его foreach.

0 голосов
/ 12 августа 2010

вы можете попробовать поместить ваши переменные в массив и получить логическое значение, которое говорит, нужно ли вам добавлять «И» перед следующей фразой. Это сократит ваши управляющие операторы до foreach и вложенного if.

...