【问题标题】:PDO prepared statement seems to ignore HAVING clausePDO 准备好的语句似乎忽略了 HAVING 子句
【发布时间】:2019-07-11 22:27:02
【问题描述】:

I've included a DB-fiddle, and you can adjust the input parameter accordingly。这将返回我所期望的结果,并且与我在 PDO 中看到的结果不同。

我有以下缩小的表格视图和查询:

CREATE TABLE `tagged` {
    `tag` SMALLINT(5) UNSIGNED NOT NULL
}

表格有各种各样的值,但您可以使用 1-10 作为 DB 中的标签:

INSERT INTO tagged (tag) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)

查询:

SELECT tagged.tag,
    (@t := :tag),
    @t AS temp_var,
    (@t IS NULL OR FIND_IN_SET(tagged.tag, @t) > 0) AS is_match
FROM tagged
HAVING is_match = 1
LIMIT 150

当在客户端、命令行、jdbc 等中运行时,这似乎很好。如果我输入''NULL,我会得到所有结果。同样,'1' 的输入只产生1 的标签,'1,4' 的输入将检索所有带有 1 或 4 的标签。

查询限制这些结果的方式是通过HAVING 子句中的is_match = 1。使用 PDO 运行时,参数似乎正确绑定,但它完全忽略了子句中的条件:

Array
(
    [0] => stdClass Object
        (
            [tag] => 3
            [(@t := ?)] => 1,4
            [temp_var] => 1,4
            [is_match] => 0     ## should not have been returned
        )

    [1] => stdClass Object
        (
            [tag] => 4
            [(@t := ?)] => 1,4
            [temp_var] => 1,4
            [is_match] => 1
        )

用于运行此程序的 PHP 代码(简化):

$conn = /* pdo connection object */;
$stmt = $conn->prepare(DB::queryOf('test')); //uses our above query from a file
$stmt->bindValue(':tag', $args['tag'], PDO::PARAM_STR); //hardcode binding '1,4'
$stmt->execute(); //also tried plain #execute($args)
return $stmt->fetchAll(PDO::FETCH_OBJ);

我有什么遗漏吗?我正在绑定一个直接字符串参数,似乎临时变量在那里并且设置正确。为什么 PDO 会返回 is_match = 0 的元素的结果?

【问题讨论】:

  • DB::queryOf() - 这不是 PDF。您应该告诉我们您正在使用哪个库。
  • 它不是一个库,只是我编写的一个函数,它加载一个.sql 文件(在本例中名为test.sql)。从字面上看,只是一个file_get_contents 电话。有问题的查询当然是在问题中。
  • 如果没有 ORDER BY 子句,这一切都毫无意义。见:Why should I provide an MCVE for what seems to me to be a very simple SQL query?
  • 您是否尝试过任何带有 HAVING 子句的简单查询?抱歉..但是您的示例不完整且太复杂。而且这个查询对我来说毫无意义。
  • 这是出现问题的简化查询,像SELECT tagged.tag FROM tagged HAVING tag = 1 这样的操作将在 PDO 中正确执行。 @PaulSpiegel

标签: php mysql pdo mariadb


【解决方案1】:

我相信这种行为取决于所使用的 RDBMS。

在没有GROUP BY子句的情况下,似乎在某些情况下,整个结果可以认为是“一组”。因为结果中的一行满足HAVING 条件,所以都应该通过。

补充阅读:

Use of HAVING without GROUP BY in SQL queries

HAVING without GROUP BY

附言我不认为> 0 是必要的。

我想我会这样写你的查询:

SELECT tag,
    @t := '1,4' AS temp_var,
    1 AS is_match
FROM tagged
WHERE @t IS NULL OR FIND_IN_SET(tag, @t)
LIMIT 150;

【讨论】:

  • 如果我的理解(最近通过研究这个问题才发现)不正确,我可以愉快地编辑或删除我的帖子。您可能想测试没有行满足的其他 HAVING 条件。
  • 我现在正在测试一些东西,这对于我提供的示例查询似乎是一个合理的修复。我现在正在尝试使解决方案适应我的实际查询(因为涉及多个表),以查看是否可以为 PDO 修复它。
  • 您在两个方面都是正确的(> 0 已删除,有意义)。为了适应我的查询,我最终不得不在我的查询中附加一个分组条件,最终看起来像GROUP BY media_source.name, media.id, tagged.media(其中tagged.media 是我们讨论的标签表中使用的媒体标识符)。然而,这完全修复了我在 HAVING 子句中专门针对 PDO 使用的比较。诡异的东西!
  • 我已经对更改后的查询添加了我的想法,但它可能对您的实际项目需求来说太基本了。
  • 你说它取决于 RDBMS。 OP 说它取决于客户端(PHP-PDO)。这是一个有趣的协议。顺便说一句:修改后的查询仍然没有意义。 select tag from tagged where tag in (1,4) 也可以达到同样的效果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-30
  • 1970-01-01
  • 2013-09-15
  • 1970-01-01
  • 1970-01-01
  • 2011-07-13
相关资源
最近更新 更多