【问题标题】:Ignore particular WHERE criteria忽略特定的 WHERE 标准
【发布时间】:2012-06-27 17:10:21
【问题描述】:

我想执行一个参数化查询以按用户提供的参数执行搜索。有很多参数,并不是所有的参数都会一直提供。如何进行标准查询来指定所有可能的参数,但如果用户没有选择有意义的参数值,则忽略其中一些参数?

这是一个虚构的例子来说明我的目标

$sql = 'SELECT * FROM people WHERE first_name = :first_name AND last_name = :last_name AND age = :age AND sex = :sex';
$query = $db->prepare($sql);
$query->execute(array(':first_name' => 'John', ':age' => '27');

显然,这不起作用,因为提供的参数数量与预期参数的数量不匹配。我是否必须每次都只在 WHERE 子句中包含指定的参数来制作查询,或者有没有办法让其中一些参数被忽略或在检查时始终返回 true?

【问题讨论】:

    标签: php mysql pdo where-clause


    【解决方案1】:
    SELECT * FROM people 
    WHERE (first_name = :first_name or :first_name is null)
    AND (last_name = :last_name or :last_name is null)
    AND (age = :age or :age is null)
    AND (sex = :sex or :sex is null)
    

    传递参数时,为不需要的参数提供null

    请注意,为了能够以这种方式运行查询,必须将 PDO 的 emulation mode 转为 ON

    【讨论】:

    • 我认为这不是他想要的。这将匹配first_name 具有匹配值,或者如果它为空。但据我了解,他希望 first_name 匹配任何内容(好像该列根本没有 WHERE 子句)。
    • @netcoder 它不检查 first_name 是否为空,它正在检查 (first_name = @var or @var is null)
    • 这正是我想要的,谢谢!相当巧妙。
    • @juergen d 如果没有不匹配的数组元素,它会给出“绑定变量的数量”PDOException。见我的comment below
    【解决方案2】:

    首先,首先将您的 $sql 字符串更改为简单的:

    $sql = 'SELECT * FROM people WHERE 1 = 1';
    

    WHERE 1 = 1 将允许您不包含任何其他参数...

    接下来,有选择地将任何具有有意义值的附加参数连接到您的 $sql 字符串:

    $sql .= ' AND first_name = :first_name'
    $sql .= ' AND age = :age'
    

    您的$sql 字符串现在只包含您计划提供的参数,因此您可以像以前一样继续:

    $query = $db->prepare($sql);
    $query->execute(array(':first_name' => 'John', ':age' => '27');
    

    【讨论】:

      【解决方案3】:

      如果您无法通过更改查询来解决问题...有几个库可以帮助您组合查询。我过去使用过Zend_Db_Select,但每个框架都可能有类似的东西:

      $select = new Zend_Db_Select;
      
      $select->from('people');
      
      if (!empty($lastName)) {
        $select->where('lastname = ?', $lastname);
      }
      
      $select->order('lastname desc')->limit(10);
      
      echo $select; // SELECT * FROM people WHERE lastname = '...' ORDER BY lastname desc LIMIT 10
      

      【讨论】:

        【解决方案4】:

        我已经测试了@juergen 给出的解决方案,但它给出了 PDOException,因为绑定变量的数量不匹配。无论没有参数,以下(不是那么优雅)代码都可以工作:

        function searchPeople( $inputArr )
        {
          $allowed = array(':first_name'=>'first_name', ':last_name'=>'last_name', ':age'=>'age', ':sex'=>'sex');
        
          $sql  = 'SELECT * FROM sf_guard_user WHERE 1 = 1';
        
          foreach($allowed AS $key => $val)
          {
              if( array_key_exists( $key, $inputArr ) ){
                  $sql .= ' AND '. $val .' = '. $key;
              }
          }
        
          $query = $db->prepare( $sql );
          $query->execute( $inputArr );
          return $query->fetchAll();
        }
        

        用法:

        $result = searchPeople(array(':first_name' => 'John', ':age' => '27'));
        

        【讨论】:

        • 您使用的是命名参数和最新版本的PHP+PDO吗?它对我来说很好。
        • 是的,我正在使用命名参数和 PHP 5.3.5 和 mysqlnd 5.0.7。上面的代码工作正常,但如果我只用@juergen d 替换 $sql 字符串,则会出现 PDOException。他的方法当然更优雅,我更喜欢使用它。知道可能出了什么问题吗?
        • 您必须为不需要的参数提供 null。
        • 是的。这就解释了。我以为你想要一个可变的数组大小作为输入。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多