2010-08-12 22 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

相关问题