如何在 MySQL 排序中控制 nulls-first 或 nulls-last?
Posted
技术标签:
【中文标题】如何在 MySQL 排序中控制 nulls-first 或 nulls-last?【英文标题】:How to control nulls-first or nulls-last in MySQL sorting? 【发布时间】:2017-11-02 09:32:24 【问题描述】:我的数据如下所示:
App ID Ref Id App Type Reg Date
1 1 Main 2017-05-13
2 2 Sub 2017-05-14
3 1 Sub 2017-05-16
4 2 Main 2017-05-15
5 3 Main 2017-05-14
6 1 sub 2017-05-17
7 null Main 2017-05-20
我想按如下所示更改此表。
App ID Ref Id App Type Reg Date
7 null Main 2017-05-20
4 2 Main 2017-05-15
2 2 Sub 2017-05-14
5 3 Main 2017-05-14
1 1 Main 2017-05-13
6 1 sub 2017-05-17
3 1 Sub 2017-05-16
显示具有相同 ref ID 的内容,具有 Main 的内容位于顶部。最近注册的内容必须在顶部。也就是说,我想创建一个层次结构。
我配置了如下所示的查询。
SELECT *
FROM t
JOIN (SELECT `Ref Id`, MAX(`Reg Date`) AS maxdate FROM t WHERE `App Type` = 'Main' GROUP BY 1) md USING(`Ref Id`)
ORDER BY maxdate DESC, `Ref Id`, (`App Type` = 'Main') DESC;
但是,结果如下。即使 Ref Id 为空,我也会按 Reg Date 排序。总之,要配置为第二张表,数据7应该在最上面。
App ID Ref Id App Type Reg Date maxdate
4 2 Main 2017-05-15 2017-05-15
2 2 Sub 2017-05-14 2017-05-15
5 3 Main 2017-05-14 2017-05-14
1 1 Main 2017-05-13 2017-05-13
6 1 sub 2017-05-17 2017-05-13
3 1 Sub 2017-05-16 2017-05-13
7 null Main 2017-05-20 null
【问题讨论】:
请使用引号使您的信息可读。另外,如果你能以表格形式发布结果,那就更好了。 问题是由于空Ref Id
导致子查询的连接失败。也许你可以用ORDER BY COALESCE(maxdate,'Reg Date')
代替ORDER BY maxdate
。
最后一条评论应该在Reg Date
周围加上反引号而不是单引号,但我不知道如何防止对格式做奇怪的事情。
@SteveLovell 我已经通过添加该部分解决了这个问题。ORDER BY COALESCE(maxdate,'Reg Date') 谢谢。
【参考方案1】:
你快到了,使用left join
获取所有记录,尝试以下操作:
SELECT t.*
FROM t
LEFT JOIN (
SELECT `Ref Id`, MAX(`Reg Date`) AS maxdate
FROM t
WHERE `App Type` = 'Main'
GROUP BY 1
) md USING(`Ref Id`)
ORDER BY t.`Ref Id` is not null, maxdate DESC, (`App Type` = 'Main') DESC, t.`Reg Date` DESC;
【讨论】:
【参考方案2】:重写我之前的评论作为答案,并提供更多背景信息和建议。我觉得代码应该大致如下:
SELECT
t.*,
md.MaxDate
FROM
t
LEFT JOIN
(
SELECT
`Ref Id` as RefId,
MAX(`Reg Date`) AS MaxDate
FROM t
WHERE
`App Type` = 'Main'
GROUP BY
RefId
) md ON md.RefId = t.`Ref Id`
ORDER BY
COALESCE(md.MaxDate, t.`Reg Date`) DESC,
t.`Ref Id`,
(t.`App Type` = 'Main') DESC;
关于连接的思考
您会注意到我已将您的“自然连接”替换为标准(左外)连接。我非常喜欢 Natural Joins 的优雅,但似乎有充分的理由不使用它们(请参阅this SO 问题和各种答案)。
我猜您实际上已经将其作为外部联接,否则我希望您的代码根本不会返回有问题的行(因为 `Ref Id` is NULL
这就是您要加入的)...和 AFAIK,mysql 中没有 ANSI_NULLS OFF
选项。
对此的思考
现在,我将评论转换为答案的主要原因是指出此解决方案可能存在的问题。很大程度上取决于记录具有`Ref Id` = NULL
的原因,以及在这种情况下还能预期什么。如果您有NULL
s,其中既有'Main'
的`App Type`
和'Sub'
的`App Type`
,那么由于`Reg Date`
不同,它们可能会相互分离。其他相关记录显示在连续行中,因为它们按共享的MaxDate
排序,由子查询检索,但在这种情况下,子查询失败并使用`Reg Date`
作为代理。
如果额外的'Sub'
类型记录仅在分配`Ref Id`
之后出现,这不会有问题。
如果发生这种情况,那么您需要另一种方法在子查询中将这些行绑定在一起。不知道数据,不知道能不能用。
附:天哪,我真的不喜欢所有这些反引号。如果列名中没有空格,则不需要它们。如果您问我,这是避免在开头放置这些空格的绝佳理由(如果这是您的决定)。
【讨论】:
以上是关于如何在 MySQL 排序中控制 nulls-first 或 nulls-last?的主要内容,如果未能解决你的问题,请参考以下文章