【问题标题】:Alternative to setting variables in SELECT for MySQL 8在 SELECT for MySQL 8 中设置变量的替代方法
【发布时间】:2022-10-05 16:42:37
【问题描述】:

我有一个上下文,我需要能够在 MySQL 5 和 8 下运行相同的查询。运行以下 SQL 查询时:

SET
    @item_row := 0,
    @var_row := 0;
SELECT
    *
FROM
    (
        SELECT
            @item_row := @item_row + 1 AS `row_nr`,
            `id` AS `order_item_id`
        FROM
            `order_items`
        WHERE
            `order_id` = ?
    ) `items`
    INNER JOIN (
        SELECT
            @var_row := @var_row + 1 AS `row_nr`,
            `index_number`
        FROM
            `recipe_variables`
        WHERE
            `recipe_variables`.`order_id` = ?
            AND `recipe_variables`.`index_number` = 1
    ) `vars` USING (`row_nr`)
    INNER JOIN `order_items`
    ON `order_items`.`id` = `items`.`order_item_id`
WHERE
    `items`.`order_item_id` = ?

我收到以下警告:

setting user variables within expressions is deprecated and will be removed in a future release

而且结果不正确。然而,只有在一个运行 MySQL 8 的环境下。在另一台运行 MySQL 8 的服务器上它工作正常,而在另一个运行 MySQL 5 的服务器上,它也能正常工作而没有警告。

我知道我可以改用ROW_NUMBER() OVER () 来重写查询以不使用变量,但是旧的 MySQL 5 服务器不支持这一点,我暂时不允许更新。

我检查了它们的完整版本,两个 MySQL 8 数据库都返回 8.0.25(使用 SELECT VERSION())。什么会导致这种差异?以及如何更改我的查询,使其仍然向后兼容 MySQL 5,但在 MySQL 8 下运行时没有警告?

  • 您是否尝试过设置像@item_row := @item_row + 1 as row_nr 这样的变量而不是(SELECT @item_row + 1 INTO @item_row) AS row_nr
  • 啊,哎呀,我本来打算写@item_row := @item_row + 1 as row_nr。按照警告的建议,我复制了我尝试使用INTO 的测试用例。不幸的是,不允许将SELECT ... INTO 查询作为子查询,因此测试失败。
  • 该变量应该在两个版本中都有效。正如消息所说,它已被弃用,但尚未删除。结果在哪些方面不正确?您可以在每个版本中发布示例数据和结果吗?
  • 在使用变量的任何一个子查询中都没有ORDER BY,因此分配数字的顺序是不可预测的。没有理由期望跨版本保持一致。
  • 你是如何检查版本的?您应该使用SELECT VERSION(); 来获取 MySQL 服务器的版本。无论您做什么,都可能返回您使用的客户端版本。

标签: mysql


【解决方案1】:

关键错误是在存在计数器变量的情况下使用WHERE 而不是HAVING,这导致row_nr 始终解析为1,因为过滤器始终最多产生1 条记录(唯一标识符)。显然,MySQL 5 和 8 的语义在这方面有所不同,因为无论您使用 WHERE 还是 HAVING,版本 5 的行为都是相同的。

使用HAVING,它现在可以在不同环境中始终如一地工作,除了警告仍然出现在一个环境中,但这足以满足我的需要。最好的解决方案是升级旧的 MySQL 5 服务器并重写查询以使用 ROW_NUMBER() OVER (),这将在几个月后发生,所以我现在可以忍受一些警告。

我确实按照@Barmar 的建议添加了ORDER BY 子句,就好像它在实践中按插入顺序返回记录一样,根据MySQL 的语义,我实际上并没有这个保证,所以最好只添加它们以确保( ORDER BY id ASC)。我还添加了LIMIT,否则根据语义不需要遵守ORDER BY,就像我在想要group by an ordered subquery in MariaDB 时遇到的那样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-12
    • 1970-01-01
    • 2012-02-04
    • 1970-01-01
    • 2014-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多