2010-08-12 23 views
7

我必須建立一個基於特定條件的查詢。有沒有比我在下面做的方式更好的做法?它可以正常工作,但是如果有更多的條件,我可以很快地看到它失控,因爲我檢查是否有任何先前的條件在每次檢查新條件時都滿足。建立一個長查詢,並有很多if語句 - 是否有更優雅的方式?

$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')"; 
     } 

    } 
+0

這是一個很好的問題:) – dmp 2010-08-12 18:54:56

回答

6

我會用舊的"WHERE 1=1"把戲;將此作爲第一個條件添加,然後您可以對每個後面的語句採用「AND」條件。

+0

@Palpie已經在他的回答中證明了這種方法的實際用法。 – DanP 2010-08-13 19:06:46

0

你可以嘗試把在數組變量和具有布爾值,如果你需要你的下一個詞組之前添加的「AND」,告訴。這會將控制語句縮短爲foreach並嵌套if。

0

這裏是我的解決方案:

$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

此代碼很難閱讀。 – 2010-08-13 07:40:58

1

建立一個列表/條件數組,其中每個條件是可選的(即,如果條件有效,則將其推入列表中)。

如果此列表> 0,請添加「where」,然後添加「and」加入的列表。

0

不幸的是,構建動態SQL是一個乏味的體驗,即使您可以在邏輯中更改一些東西(實際上看起來相對乾淨),它仍然會很難看。

幸運的是,Object-relational mapping存在。我對PHP不太熟悉,但Perl有幾個CPAN模塊,例如SQL :: Abstract,它允許您使用基本數據結構來構建相當複雜的SQL語句。

+0

我們不知道系統birderic創建的大小。這裏可能涉及ORM和SQL構造函數不是最優的。 – 2010-08-13 07:42:32

1

而不是做這樣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招這也將工作在這種情況下不起作用,甚至可能證明是非常危險的)。

4
$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')"; 
+0

謝謝你的示例實現+ 1 – DanP 2010-08-13 19:25:35

0

如果使用存儲過程,你可以做這樣的事情:

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是OK。 _day的任何其他值,必須匹配。我假設fldDay是文字,但當然你可以在這裏正確輸入。

我知道有些人不是存儲過程的粉絲,但它可以用這種方式方便地封裝查詢邏輯。

+0

我想它會用準備好的語句的工作也一樣,如果你寫的where子句了這種方式,並結合各自的參數'?'S的。 – grossvogel 2010-08-12 22:17:07

相關問題