MySQL中的OR逻辑

时间:2016-02-28 20:03:32

标签: php mysql sql database get

我有一张简单的桌子 http://i.stack.imgur.com/yR3xP.jpg

通过 $ Poles OR $ Power(或两者的组合)我选择行列表

if($_GET["Power"]!="*" and $_GET["Poles"]!="*") $query = "SELECT * FROM `TABLE 2` WHERE Power=".$_GET["Power"]." AND Poles=".$_GET["Poles"]."";
elseif($_GET["Poles"]!="*") $query.= "SELECT * FROM `TABLE 2` WHERE Poles=".$_GET["Poles"]."";
elseif($_GET["Power"]!="*") $query.= "SELECT * FROM `TABLE 2` WHERE Power=".$_GET["Power"]."";
else $query= "SELECT * FROM `TABLE 2` ORDER BY Power";

我绝对是初学者,但我觉得这是一种错误的做法。

请告诉我,应该怎么做?

  1. 如果设置了Power并且Poles是* - 我想要所有具有此功率的行。
  2. 如果Poles已设置且Power为* - 我希望所有行都有此极点。
  3. 如果两者都设置为任何值 - 我想看到这个确切的行;
  4. 如果两者都设置为* - 我想要表中的所有行

2 个答案:

答案 0 :(得分:3)

只要提供的信息,我认为您的逻辑通常可以实现您的目标。你有几个场景对我来说是截然不同的查询,所以我会处理用PHP构建查询的逻辑。

我不确定你是否使用任何类型的框架,但我会假设你不是,但我建议你这样做是否可行。一个好的框架将提供输入清理和数据库管理,使生活更轻松,并提供更多安全选项。

出于安全考虑,由于您使用直接来自用户的输入构建查询,我建议您使用PDO类与数据库进行交互(如果不是)。 PDO类将允许您将用户的输入绑定到查询,然后它将自动转义输入。这大大降低了SQL注入攻击的风险(用户使用他们向您提交的内容向您的数据库执行恶意操作),现在被认为是PHP的标准做法。

有关PDO课程的更多信息,请访问:http://php.net/manual/en/book.pdo.php

有关SQL注入攻击的更多信息,请访问:http://www.w3schools.com/sql/sql_injection.asp

所以这将是我未经测试的代码将它们放在一起:

$dsn = "localhost"; //Where is your DB located?
$username = "username";
$password = "password";

//Create new DB connection (http://php.net/manual/en/pdo.construct.php)
$dbh = new PDO($dsn, $username, $password);

//Craft and execute the appropriate query
//Each query will include placeholders for data (like :power)
//Placeholders will be replaced with the data passed to execute()
//The PDO class will escape the user input to prevent SQL injection
if ($_GET["Power"] != "*" && $_GET["Poles"] != "*") {
    $stmt = $dbh->prepare("SELECT * FROM `TABLE 2` WHERE `Power` = :power AND `Poles` = :poles;");
    $stmt->execute([
        ':power' => $_GET["Power"],
        ':poles' => $_GET["Poles"]
    ]);
} elseif ($_GET["Power"] != "*") {
    $stmt = $dbh->prepare("SELECT * FROM `TABLE 2` WHERE `Power` = :power");
    $stmt->execute([':power' => $_GET["Power"]]);
} elseif ($_GET["Poles"]) {
    $stmt = $dbh->prepare("SELECT * FROM `TABLE 2` WHERE `Poles` = :poles;");
    $stmt->execute([':power' => $_GET["Poles"]]);
} else {
    $stmt = $dbh->prepare("SELECT * FROM `TABLE 2` ORDER BY `Power` ASC");
    $stmt->execute();
}

if ($stmt->rowCount()) {
    //The query returned results, which we can fetch in a variety of ways
    //http://php.net/manual/en/pdostatement.fetch.php
    //http://php.net/manual/en/pdostatement.fetchall.php
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
} else {
    //No results, handle appropriately
}

如果if / elseif / else块看起来很粗糙,你实际上可以用switch语句完成同样的事情。将true作为要匹配的值传递,并使您的case语句成为定义每个案例的逻辑。匹配的第一个案例将运行,而如果没有案例匹配则默认运行。

这就是看起来的样子:

switch (true) {
    case $_GET["Power"] != "*" && $_GET["Poles"] != "*":
        $stmt = $dbh->prepare("SELECT * FROM `TABLE 2` WHERE `Power` = :power AND `Poles` = :poles;");
        $stmt->execute([
            ':power' => $_GET["Power"],
            ':poles' => $_GET["Poles"]
        ]);
        break;
    case $_GET["Power"] != "*":
        $stmt = $dbh->prepare("SELECT * FROM `TABLE 2` WHERE `Power` = :power");
        $stmt->execute([':power' => $_GET["Power"]]);
        break;
    case $_GET["Poles"] != "*":
        $stmt = $dbh->prepare("SELECT * FROM `TABLE 2` WHERE `Poles` = :poles;");
        $stmt->execute([':power' => $_GET["Poles"]]);
        break;
    default:
        $stmt = $dbh->prepare("SELECT * FROM `TABLE 2` ORDER BY `Power` ASC");
        $stmt->execute();
        break;

修改1:

对于它的价值,我倾向于避免尽可能多地暴露我的任何底层技术,因此使用用户可以看到和可能操作的默认SQL关键字/运算符是有问题的(对我而言)。因此,我不使用*或%作为用户可以传递给我的值。取而代之的是我可以在我的逻辑中使用其他占位符,例如空字符串,0或-1,具体取决于字段接受的内容。

使用PDO和绑定参数可以抵消用户输入恶意内容的风险,因此仅仅这样做会消除使用*或%的大量风险。在这种情况下,它只取决于您是否希望用户能够猜测您的底层存储引擎。

从性能的角度来看,我相信在WHERE子句中,相等运算符(=)将比LIKE运算符更快,但您可能只会注意到大型生产环境中的性能损失,因此不必担心。< / p>

答案 1 :(得分:1)

$query = "SELECT * FROM `TABLE 2` WHERE Power LIKE ".$_GET["Power"]." AND Poles LIKE ".$_GET["Poles"]."";

使用此查询将能够获得您想要的结果。请注意,我已将=运算符更改为LIKE

然后,在您的用户表单或将值传递到$_GET的方式中,您需要将*更改为%%是MySQL的wilcard符号。

<强>另外

您在数据库查询中使用来自用户的输入,因此您应该始终使用预准备语句来避免SQL注入。

请参阅This SO Q&A哪两个非常容易遵循如何执行适当准备陈述的样本