可以让PHP MYSQL查询忽略WHERE子句中的空变量吗?

时间:2012-09-09 13:44:16

标签: php mysql where clause

不确定我该怎么做。基本上我有变量用组合框填充,然后传递以通过where子句形成MQSQL查询的过滤器。我需要做的是允许用户将组合框留空,然后在where子句中忽略该变量。这可能吗?

即,来自此代码。假设填充$ value1的组合框保留为空,是否有任何方法可以忽略它并仅应用第二个过滤器。

$query = "SELECT * FROM moth_sightings WHERE user_id = '$username' AND location = '$value1' AND english_name = $value2 ";
$result = mysql_query($query) or die(mysql_error());
$r = mysql_numrows($result);

感谢您的帮助。 ç

7 个答案:

答案 0 :(得分:12)

使用

$where = "WHERE user_id = '$username'";

if(!empty($value1)){
$where .= "and location = '$value1'";
}

if(!empty($value2 )){
$where .= "and english_name= '$value2 '";
}


$query = "SELECT * FROM moth_sightings $where";
$result = mysql_query($query) or die(mysql_error());
$r = mysql_numrows($result);

答案 1 :(得分:1)

其他几个答案都提到了SQL注入的风险,还有几个答案明确地提到了使用预准备语句,但是没有一个明确说明如何执行,这对于初学者可能是一个很大的要求。

我当前解决此问题的首选方法是使用MySQL“ IF”语句检查所涉及的参数是否为null / empty / 0(取决于类型)。如果为空,则将字段值与其自身进行比较(WHERE field1=field1始终返回true)。如果参数不为空/空/零,则将字段值与参数进行比较。

因此,这是一个使用MySQLi预准备语句的示例(假设$ mysqli是已实例化的mysqli对象):

$sql = "SELECT * 
        FROM moth_sightings 
        WHERE user_id = ? 
            AND location = IF(? = '', location, ?)
            AND english_name = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('ssss', $username, $value1, $value1, $value2);
$stmt->execute();

(我假设$value2是基于字段名称的字符串,尽管OP的示例SQL中没有引号。)

MySQLi中无法将同一参数绑定到语句中的多个占位符,因此我们必须显式绑定$value1两次。在这种情况下,MySQLi的优点是显式键入参数-如果我们将$value1作为字符串传递,我们知道我们需要将其与空字符串''进行比较。如果$value1是整数值,我们可以像这样明确声明:

$stmt->bind_param('siis', $username, $value1, $value1, $value2);

,然后将其与0进行比较。

这是一个使用命名参数的PDO示例,因为我认为它们会导致更少的计数而使代码更具可读性:

$sql = "SELECT * 
    FROM moth_sightings 
    WHERE user_id = :user_id 
        AND location = IF(:location_id = '', location, :location_id)
        AND english_name = :name";
$stmt = $pdo->prepare($sql);
$params = [
    ':user_id' => $username,
    ':location_id' => $value1,
    ':name' => $value2
];
$stmt->execute($params);

请注意,使用PDO命名参数,我们可以在查询中多次引用:location_id,而只需绑定一次即可。

答案 2 :(得分:0)

当然,

$sql = "";
if(!empty($value1))
  $sql = "AND location = '{$value1}' ";
if(!empty($value2))
  $sql .= "AND english_name = '{$value2}'";

$query = "SELECT * FROM moth_sightings WHERE user_id = '$username' {$sql} ";
$result = mysql_query($query) or die(mysql_error());
$r = mysql_numrows($result);

注意sql注入和弃用mysql_ *,改用mysqli或PDO

答案 3 :(得分:0)

if ( isset($value1) )
 $query = "SELECT * FROM moth_sightings WHERE user_id = '$username' AND location = '$value1' AND english_name = $value2 ";
else
 $query = "SELECT * FROM moth_sightings WHERE user_id = '$username' AND english_name = $value2 ";   

但是,您还可以创建一个函数来根据您的输入返回查询。 并且在生成查询之前也不要忘记逃避$values

答案 4 :(得分:0)

1。)不要使用简单的mysql php扩展,使用高级mysqli扩展或更安全的PDO / MDB2包装。

2。)不要像那样指定完整的语句(除了你甚至不编码和转义给定的值...)。而是使用这样的东西:

sprintf("SELECT * FROM moth_sightings WHERE 1=1 AND %s", ...);

然后使用包含实际从表单中获取的所有值的数组填充该原始查询:

$clause=array(
  'user_id="'.$username.'"',
  'location="'.$value1.'"',
  'english_name="'.$value2.'"'
);

您可以以任何方式操纵此数组,例如测试空值或其他任何方式。现在只是破坏数组来完成上面的原始问题:

sprintf("SELECT * FROM moth_sightings WHERE 1=1 AND %s", 
        implode(' AND ', $clause) );

大优势:即使子句数组完全为空,查询语法也是有效的。

答案 5 :(得分:0)

首先,请阅读SQL Injections。 其次,$ r = mysql_numrows($ result)应为$ r = mysql_num_rows($ result);

您可以在MySQL中使用IF,如下所示:

SELECT * FROM moth_sightings WHERE user_id = '$username' AND IF('$value1'!='',location = '$value1',1) AND IF('$value2'!='',english_name = '$value2',1); -- BUT PLEASE READ ABOUT SQL Injections. Your code is not safe.

答案 6 :(得分:0)

我想到了另外两种方法来解决这个问题:

SELECT * FROM moth_sightings
WHERE
      user_id = '$username'
      AND location = '%$value1%'

      AND english_name = $value2 ";

这将仅返回此user_id的结果,其中位置字段包含$value1如果$ value1为空,这仍将返回此user_id的所有行,空白或不空白。

<小时/>

SELECT * FROM moth_sightings
WHERE
      user_id = '$username'
      AND (location = '$value1' OR location IS NULL OR location = '')
      AND english_name = $value2 ";

这将为您提供此user_id的所有行,其$value1位置或空值。