SQL 代码问题

1 mysql

我正在帮助一位朋友找出一些 SQL 代码,但无法弄清楚为什么它不能正常工作。

我提出了许多有效的解决方案,但我想知道为什么这个解决方案不起作用。

任何帮助,将不胜感激。

SELECT test_id,
    question_id
FROM test
WHERE test_id = 6117
GROUP BY test_id
HAVING question_id = MAX(question_id);
Run Code Online (Sandbox Code Playgroud)

他想获得特定测试的最大问题 ID。我真的不明白他为什么要这样做 - 沿着性能和功能以及子查询的路线。所以我不确定那部分,尽管听起来它会与其他 SQL 代码一起使用。

如果删除 where 子句,它适用于所有测试 ID,但是当您尝试指定测试 ID 时,它不起作用。

jka*_*lik 5

带有 GROUP BY 的查询中的选定列可以是“分组”列之一,功能上依赖于这些列或聚合。我昨天在这个答案中介绍了函数依赖。question_id不满足其中任何一个,所以把它放在那里会导致“未定义的行为”。

为了显示真正发生的事情,我准备了sql fiddle,您可以在其中看到第一个查询没有返回任何内容,第二个查询显示实际发生的事情的详细信息 - 通过删除 HAVING 并向 SELECT 添加一些列,我显示了分配给的值哪些列和表达式:

+---------+-------------+
| test_id | question_id |
+---------+-------------+
|       6 |          54 |
|       6 |         300 |
+---------+-------------+

SELECT test_id,
    question_id,
    max(question_id),
    group_concat(question_id)
FROM test
WHERE test_id = 6
GROUP BY test_id;

+---------+-------------+------------------+---------------------------+
| test_id | question_id | max(question_id) | group_concat(question_id) |
+---------+-------------+------------------+---------------------------+
|       6 |          54 |              300 | 54,300                    |
+---------+-------------+------------------+---------------------------+
Run Code Online (Sandbox Code Playgroud)

因为test_id = 6我们有两行question_id54 和 300,由于 GROUP BY 我们只能为给定的每列选择一个值test_id

  • max() 是微不足道的,它选择 300
  • group_concat() 是聚合函数,它获取组中给定列的所有可能值,并制作它们的逗号分隔列表
  • question_id是一个有趣的例子 - 它只能显示一个值,但给定的值存在两个test_id- 所以一个是“随机”选择的 - 正如我们所看到的,mysql 选择它得到的第一个 - group_concat 显示内部“排序”,但这取决于在很多事情上,其中之一是使用索引 - 这就是为什么删除 WHERE 会以这种方式更改结果,使用不同的索引,因此为该列选择了不同的数字

当您将相同的列和表达式写入 HAVING 子句时,很可能会使用相同的值,正如您所看到的,question_id != max(question_id)因为54 != 300.

为了正确解决这个任务,需要一些“groupwise-max”解决方案。它甚至包含在 MySQL手册中,其中显示了 3 种可能的解决方案 - 相关子查询、派生表和左联接。哪个最好取决于具体情况 - 对于某些数据,子查询的使用可能比左连接更快,而对于其他数据则更慢。根据我的经验,如果您的组很少有很多项目,那么子查询通常会更好,而左连接在许多较小的组中表现更好,但您可以全部测试并亲自查看。

编辑:正如其他答案所示,如果您只选择test_idand question_id,那么max(question_id)andGROUP BY test_id就足够了。我添加了上一段是因为您在某个版本的问题中提到您的朋友在子查询等方面存在一些“问题”,所以我认为实际问题并不像这样简单。