【问题标题】:Searching in SQL per POST-Variable in joined Table在连接表中搜索每个 POST 变量的 SQL
【发布时间】:2016-07-23 19:41:33
【问题描述】:

我尝试解决了一段时间,但没有找到解决方案。

我从一个充满移动设备的表格中读取并列出它们,并让用户可以根据移动设备名称和用户名搜索列表。

这是我的代码:

        SELECT
        *
    FROM
        tbl_mobdev
    LEFT JOIN
        tbl_mobdev_type ON mobdev_type_id = mobdev_type
    LEFT JOIN
        tbl_marke ON marke_id = mobdev_type_marke
    LEFT JOIN
        tbl_user ON tbl_user.id = mobdev_user
    WHERE
        CONCAT(tbl_marke.marke_name,' ',tbl_mobdev_type.mobdev_type_bezeichnung) LIKE '%".$_POST['marke_name']."%'
    AND
        CONCAT(tbl_user.name,' ',tbl_user.vorname) LIKE '%".$_POST['user']."%'
    AND
        mobdev_aktiv = '1'
    ORDER BY
        ".$_GET['sort']." ".$_GET['sort2']."

只要 tbl_mobdev.mobdev_user 包含用户 ID,一切都按预期工作,而不包含用户 ID 的表行将被忽略。

有什么解决办法吗?

编辑:将“过滤器”放在 tbl_user 的 LEFT JOIN 中的解决方案不起作用。将显示每行中类似以下结果的 SQL。 如果 LIKE 包含仅不匹配结果的内容,则不会连接该行。

SELECT mobdev_id, mobdev_type_bezeichnung, marke_name, tbl_user.name AS  user_name, tbl_user.vorname AS user_vorname
FROM tbl_mobdev
LEFT JOIN tbl_mobdev_type ON mobdev_type_id = mobdev_type
LEFT JOIN tbl_marke ON marke_id = mobdev_type_marke
LEFT JOIN tbl_user ON tbl_user.id = mobdev_user
AND CONCAT( tbl_user.name, ' ', tbl_user.vorname ) LIKE '%%'
WHERE CONCAT( tbl_marke.marke_name, ' ', tbl_mobdev_type.mobdev_type_bezeichnung ) LIKE '%%'
AND mobdev_aktiv = '1'
ORDER BY marke_name ASC 
LIMIT 0 , 30

Edit2:将 SQL 设置为以下并没有改变行为。

SELECT mobdev_id, mobdev_type_bezeichnung, marke_name, tbl_user.name AS user_name, tbl_user.vorname AS user_vorname
FROM tbl_mobdev
LEFT JOIN tbl_mobdev_type ON mobdev_type_id = mobdev_type
LEFT JOIN tbl_marke ON marke_id = mobdev_type_marke
LEFT JOIN tbl_user ON tbl_user.id = mobdev_user
AND CONCAT( tbl_user.name, ' ', tbl_user.vorname ) LIKE '%G%'
WHERE CONCAT( tbl_marke.marke_name, ' ', COALESCE( tbl_mobdev_type.mobdev_type_bezeichnung, '' ) ) LIKE '%%'
AND mobdev_aktiv = '1'
ORDER BY marke_name ASC 
LIMIT 0 , 30

不匹配 $_POST['user'] 的行仍然不会被过滤掉。

我上传了一张名称模糊的行为示例图片,左图是没有任何过滤器的 Select,右图是具有实际用户名的 Select(模糊,但它的名称与 mobdev_id '3 中的完全相同'。

http://fs5.directupload.net/images/160404/tmdbyzws.png

如您所见,其他五行仍然存在,只是没有连接。我希望它们完全消失,因为它们与过滤器不匹配。

Edit3:好吧,我现在做到了……遗憾的是,使用 PHP 的方式非常肮脏。我只是把代码留在这里,如果有人对此提出更好的解决方案,请告诉我。

$query = "
    SELECT
        mobdev_id,
        mobdev_type_bezeichnung,
        marke_name,
        tbl_user.name AS user_name,
        tbl_user.vorname AS user_vorname
    FROM
        tbl_mobdev
    LEFT JOIN
        tbl_mobdev_type ON mobdev_type_id = mobdev_type
    LEFT JOIN
        tbl_marke ON marke_id = mobdev_type_marke
    LEFT JOIN
        tbl_user ON tbl_user.id = mobdev_user
    WHERE
        CONCAT(tbl_marke.marke_name,' ',tbl_mobdev_type.mobdev_type_bezeichnung) LIKE '%".$_POST['marke_name']."%'
        ";
if($_POST['user'])
{
    $query .= "
        AND
            CONCAT(tbl_user.name,' ',tbl_user.vorname) LIKE '%".$_POST['user']."%'
        ";
}
$query .= "
    AND
        mobdev_aktiv = '1'
    ORDER BY
        ".$_GET['sort']." ".$_GET['sort2']."
    ";

【问题讨论】:

  • LEFT JOIN 时,将所有右侧表条件放在ON 子句中以获得真正的左连接行为。 (在 WHERE 中,您会得到常规的内部连接结果。)
  • 永远不要使用这个代码!!!这是一个地狱般的 SQL 注入门!首先重新考虑如何获取用户输入并对其进行验证,使用准备好的语句!!!但永远不要在查询中使用 POST 或 GET Var!
  • 感谢您的建议,但这是一个实习生代码,使用它的人也可以直接更改源代码。

标签: sql join sql-like concat


【解决方案1】:

问题出在一行

    CONCAT(tbl_user.name,' ',tbl_user.vorname) LIKE '%".$_POST['user']."%'

您在 tbl_user 上的 LEFT JOIN 将允许主查询返回,而与该行中是否存在值无关。但是,那个特定的 WHERE 子句行有效地覆盖了它;如果 tbl_user.name 或 tbl_user.vorname 为 null,则结果将始终为 false。

如果我需要做类似的事情,我通常会将测试放在 JOIN 语句的 ON 子句中。这样,它会过滤存在的 JOINed 表,但不会在不存在的地方引起问题。

示例查询文本应确保 tbl_user 在需要时被过滤,但在未指定任何内容时不被过滤 -

SELECT
    md.mobdev_id, 
    mdt.mobdev_type_bezeichnung, 
    m.marke_name, 
    u.name AS  user_name, 
    u.vorname AS user_vorname
FROM
    tbl_mobdev md
        LEFT JOIN tbl_mobdev_type mdt
            ON mdt.mobdev_type_id = md.mobdev_type
        LEFT JOIN tbl_marke m
            ON m.marke_id = mdt.mobdev_type_marke
        LEFT JOIN tbl_user u
            ON u.id = md.mobdev_user
            AND CONCAT(u.name,' ',u.vorname) LIKE '%".$_POST['user']."%'
WHERE
    CONCAT(m.marke_name,' ',COALESCE(mdt.mobdev_type_bezeichnung,'')) 
            LIKE '%".$_POST['m.marke_name']."%'
    AND md.mobdev_aktiv = '1'
ORDER BY
    ".$_GET['sort']." ".$_GET['sort2']."

两旁 -

  • 正如 Rene M. 上面所说,此代码是一个 SQL 注入漏洞。由于其当前的应用程序,它可能是安全的,但我仍然不会推出它;有人拿走这个应用程序或代码片段,然后在没有进行全面审计的情况下将其移到网上的可能性并不小,然后你就会遇到问题。练习正确的做法 - 不要在代码中留下 SQL 注入漏洞。
  • 请给您的表名取别名!为每个字段引用完整写出每个表名的查询使其非常庞大。

【讨论】:

  • 感谢您的回答。这是我之前想到的,这个解决方案的问题是应该过滤掉的行没有被过滤掉。它只显示每一行,不管 $_POST['user'] 中有什么。它只会停止 LEFT JOIN 的工作。
猜你喜欢
  • 2018-06-26
  • 2013-09-01
  • 2020-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-04
  • 2019-02-26
  • 1970-01-01
相关资源
最近更新 更多