簡體   English   中英

可以讓 PHP MYSQL 查詢忽略 WHERE 子句中的空變量嗎?

[英]Possible to have PHP MYSQL query ignore empty variable in 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);

謝謝你的幫助。 C

采用

$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);

其他幾個答案提到了 SQL 注入的風險,有幾個答案明確提到了使用准備好的語句,但沒有一個明確說明如何做到這一點,這對初學者來說可能是一個很大的要求。

我目前解決這個問題的首選方法是使用 MySQL 的“IF”語句來檢查有問題的參數是否為空/空/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而只需要綁定一次。

當然,

$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

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

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) );

大優勢:即使子句數組完全為空,查詢語法也是有效的。

首先,請閱讀SQL 注入 其次,$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.

我想到了另外兩種方法來解決這個問題:

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

      AND english_name = $value2 ";

這將僅返回此user_id結果,其中 location 字段包含$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的位置或具有空白值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM