【问题标题】:Using variables in multiple "NOT IN" clauses在多个“NOT IN”子句中使用变量
【发布时间】:2019-08-10 12:32:21
【问题描述】:

我就是无法做到这一点。作为一个爱好程序员做一个爱好项目。这是我在 php 网页上使用的 MySQL 语句:

$stmt = $mysqli->prepare("SELECT t1.* FROM laptimes t1
JOIN (
SELECT gamertag, track, vehicle, vehicleclass, platform, controller, setup, 
MIN(laptime) AS min_laptime
FROM laptimes 
WHERE track LIKE ? AND vehicle LIKE ? AND vehicleclass LIKE ? AND platform 
NOT IN ('PS4','XB1') AND controller NOT IN ('Gamepad','Keyboard') AND setup 
NOT IN ('Custom') 
GROUP BY gamertag, vehicle, vehicleclass
) AS t2 ON t1.gamertag = t2.gamertag AND t1.laptime = t2.min_laptime AND 
t1.track = t2.track AND t1.vehicle = t2.vehicle AND t1.vehicleclass = 
t2.vehicleclass AND t1.platform = t2.platform AND t1.controller = 
t2.controller AND t1.setup = t2.setup
ORDER BY laptime ASC LIMIT ? OFFSET ?");
$stmt->bind_param("sssii", $trackselect, $carselect ,$classelect, $limit, $offset); 
$stmt->execute();

上面的代码,带有一些硬编码的值,可以正常工作。它为每个玩家获得最好的单圈时间,用于排行榜。它不包括平台值“PS4”或“XB1”、控制器值“游戏板”或“键盘”以及设置值“自定义”的结果。但我想做的是用变量替换 WHERE 子句中的硬编码值。我可以用 ?对于track、vehicle、vehicleclass以及limit和offset,使用绑定参数,没问题。但是对于平台、控制器和设置,我不能使用变量,尽管代码可以很好地处理硬编码的值。

三个 NOT IN 子句排除具有这些值的记录。在示例中,platform NOT IN ('PS4',XB1') 排除了“平台”列中具有 PC 或 PS4 值的结果。我想使用 $platform、$controller、$setup,而不是硬编码值。我已经尝试过大括号、括号、反引号、撇号、双引号的所有组合;似乎没有任何效果。

如果我在例如 $platform 上打印值,它会显示:'PS4','XB1'(只是一个示例,值由复选框设置。所以它看起来等于我的硬编码值。

如果我将硬编码值替换为 ? (相应地调整 bind_param),即使我勾选复选框(我打印了 $platform、$controller、$setup 的值,它看起来也正确),也不会从结果中排除任何内容。

如果我改为这样做:platform NOT IN ($platform) 那么它就可以了。但是,如果我对控制器和设置执行相同操作,controller NOT IN ($controller) AND setup NOT IN ($setup) 我会收到以下错误消息: Fatal error: Call to a member function bind_param() on a non-object 指向带有 bind_param 的行。我已经调整了 bind_param 行以更正“sss”和 $variables 的数量。

那么如何使用变量而不是硬编码值呢?

我在这方面已经超出了我的水平,我无法理解。打印的变量值与硬编码示例完全相同。我需要一种特殊的括号,还是某种魔法酱?我不知道。 希望我已经很好地解释了这个问题。如果没有,请告诉我,我会再试一次。

【问题讨论】:

  • “但是对于平台、控制器和设置,我不能使用变量,尽管代码可以很好地处理硬编码的值。” 我非常怀疑这一点,因为内部查询不正确 MySQL 的 Handling of GROUP BY,如果 MySQL 执行它没有错误,您不能相信平台、控制器和设置列在此查询中具有正确的值。
  • 感谢您的回答。你认为内部查询问题是我问题的原因吗?或者这是一个不同的问题?对于硬编码的值,它确实可以按预期工作。如果这很重要,我不确定如何证明这一点。
  • NOT IN (?, ?, ?) 工作得很好。您的代码中的其他地方可能有错字。我强烈建议使用 PDO 或完整的数据库抽象层而不是 mysqli。该 API 是 MySQL C API 的低级映射,不适合直接使用。
  • "那个API是MySQL C API的底层映射,不适合直接使用" mysqli很好@miken32顺便也支持OOP接口..
  • 您可以使用NOT FIND_IN_SET(controller, ?),然后为参数提供一个类似'Gamepad,Keyboard' 的字符串。

标签: php mysql join where


【解决方案1】:

如果字符串中有逗号分隔的值列表,则可以使用FIND_IN_SET() 匹配其中一个。您使用绑定参数作为列表的字符串。

所以使用:

$controller = 'Gamepad,Keyboard';
$platform = 'PS4,XB1';
$setup = 'Custom';

然后让您的查询使用:

AND NOT FIND_IN_SET(platform, ?) 
AND NOT FIND_IN_SET(controller, ?) 
AND NOT FIND_IN_SET(setup, ?)

并将这些参数绑定到上述变量。

【讨论】:

  • 我昨天的评论好像消失了?无论如何,这很好用,太棒了!谢谢!
【解决方案2】:

您正试图将IN() 中的多个值与一个变量绑定。参数化需要文字值与绑定值的一对一匹配。因此,您的以下尝试:

$platform = "'PS4','XB1'"
...

WHERE ... platform NOT IN (?)

应替换为:

$platform1 = 'PS4'
$platform2 = 'XB1'
...

WHERE ... platform NOT IN (?, ?)

很可能,您希望将 qmarks 动态放置在 IN() 中并动态绑定需要使用操作数组的多个变量。此类问题已在 PHP on SO 中被多次询问和回答:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-17
    • 2016-10-02
    相关资源
    最近更新 更多