【发布时间】:2012-01-22 05:11:10
【问题描述】:
背景
我的典型用例:
# Table
id category dataUID
---------------------------
0 A (NULL)
1 B (NULL)
2 C text1
3 C text1
4 D text2
5 D text3
# Query
SELECT MAX(`id`) AS `id` FROM `table`
GROUP BY `category`
这很好;它将删除正在处理的记录集中的所有“重复类别”,为我提供每个类别的“最高”ID。
然后我可以继续使用此 ID 再次提取所有数据:
# Query
SELECT * FROM `table` JOIN (
SELECT MAX(`id`) AS `id` FROM `table`
GROUP BY `category`
) _ USING(`id`)
# Result
id category dataUID
---------------------------
0 A (NULL)
1 B (NULL)
3 C text1
5 D text3
请注意,这不与:
SELECT MAX(`id`) AS `id`, `category`, `dataUID` FROM `table`
GROUP BY `category`
在标准 SQL 中,包含 GROUP BY 子句的查询不能引用 到选择列表中未在 GROUP BY 子句。例如,此查询在标准 SQL 中是非法的 因为选择列表中的名称列没有出现在 分组依据:
SELECT o.custid, c.name, MAX(o.payment) FROM orders AS o, customers AS c WHERE o.custid = c.custid GROUP BY o.custid;为了使查询合法,必须从 在 GROUP BY 子句中选择列表或命名。
MySQL 扩展了 GROUP BY 的使用,以便选择列表可以引用 未在 GROUP BY 子句中命名的非聚合列。 这意味着 前面的查询在 MySQL 中是合法的。您可以使用此功能 通过避免不必要的列排序来获得更好的性能和 分组。 但是,这主要在每个 未在 GROUP BY 中命名的非聚合列对于每个都相同 组。
[..]
此扩展假定未分组的列将具有相同的分组值。否则,结果是不确定的。
所以我会得到dataUID 的未指定值——例如,text2 或 text3 的结果是id 5。
在我的真实案例中,这实际上是其他领域的问题;碰巧的是,特别是对于 dataUID 列,通常我并不真正关心我得到的 哪个 值。
问题
但是!
如果给定category 的任何行具有NULL dataUID,并且至少另一行具有非NULL dataUID,我希望MAX 忽略NULL 一个。
所以:
id category dataUID
---------------------------
4 D text2
5 D (NULL)
目前,由于我选择了ID最大的行,我得到:
5 D (NULL)
但是,因为dataUID 是NULL,所以我想要:
4 D text2
我怎样才能得到这个?如何在聚合MAX 的使用中添加条件逻辑?
我想可能会交给MAX一个元组,然后将id从中拉出来:
GET_SECOND_PART_SOMEHOW(MAX((IF(`dataUID` NOT NULL, 1, 0), `id`))) AS `id`
但我认为MAX 不会接受这样的任意表达式,更不用说元组了,而且我不知道如何事后检索元组的第二部分。
【问题讨论】:
-
如果一个类别的所有行都有
dataUID NULL,会发生什么? -
@ypercube:回退到按 ID 排序。在进行排序时,我只想优先考虑确实存在于组中的任何
dataUID-present 行。 -
@ajreal:Ta。我找不到明显不合适的
max标签的替代品;) -
@ajreal: 是的,我想that's true :)
标签: mysql group-by greatest-n-per-group