如何在MySQL排序中控制nulls-first或nulls-last?

时间:2017-06-01 09:43:55

标签: mysql sql group-by sql-order-by

我的数据如下:

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

我想更改此表,如下所示。

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;

显示具有相同参考ID的内容,并且具有Main的内容位于顶部。最近注册的内容必须位于顶部。也就是说,我想创建一个层次结构。

我配置了如下所示的查询。

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为null,我也按Reg Date排序。总之,要配置为第二个表,数据7应位于顶部。

{{1}}

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分:0)

重写我之前的评论作为答案,并提供更多的背景和建议。我认为代码大致如下:

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和那个&#39}您加入的内容)...和AFAIK,MySQL中没有ANSI_NULLS OFF选项。

对此作为解决方案的想法

现在,我将评论转换为答案的主要原因是指出此解决方案可能存在的问题。很大程度上取决于记录`Ref Id` = NULL的原因,以及在这种情况下可以预期的其他内容。如果NULL `App Type` 'Main' `App Type`'Sub' `Reg Date`,那么这些可能会因为有MaxDate而彼此分开另一个`Reg Date`。其他相关记录显示在连续的行中,因为它们按子查询检索的共享'Sub'排序,但在这种情况下,子查询失败并使用`Ref Id`作为代理。

如果额外的~/.bashrc类型记录仅在分配export HISTIGNORE="&:ls:cd:lh" 后出现,那么这不会有问题。

如果发生这种情况,那么您需要另一种方法在子查询中将这些行绑定在一起。不知道数据,我不知道这是否可用。

P.S。天哪,我真的不喜欢所有这些反叛。如果您的列名中没有空格,则不需要它们。如果你问我,这是一个很好的理由避免把这些空间放在一起(如果你的决定是这样的话)。