多个mysql ORDER BY,用于多维排序/分组


Multiple mysql ORDER BY's for multidimensional ordering/grouping

我有一组数据需要同时以多种方式排序。

简化后,该表可以总结为:

任务

  • 编号
  • 组(国际)
  • 日期
  • (日期)
  • 完成 (0/1)

我需要生成这些任务的列表,主要按"完成"排序,其次按"日期"排序,然后按"组"分组

该组是导致我出现问题的原因,我有一种感觉,这可能最好用 PHP 实现,因为它可能无法作为查询的一部分 - 欢迎有关解决此问题的最佳方法的提示,它当然不必是纯 mysql。

目前我正在使用:

ORDER BY complete, group, date

这非常适合"未分组"任务,所有未完成的 (0) 任务都在顶部,完成的 (1) 任务在底部;每组完成/未完成的任务按日期排序。

但是,组最终可能会聚集在底部,在更广泛的上下文中日期顺序不正确 - 组本身不会给定其任务日期。下面是不需要的输出(已订购)的示例:

Task #2 - Group(false), Complete(0), date(2013-11-01)
Task #4 - Group(false), Complete(0), date(2013-12-01)
Task #5 - Group(1), Complete(0), date(2013-10-01)
Task #3 - Group(1), Complete(0), date(2013-12-01)
Task #1 - Group(false), Complete(1), date(2013-11-01)

如您所见,分组项目的日期排序不正确,排序发生在组。任务 #5 排在第三位,即使它的日期最早。

我希望看到的输出如下:

Task #5 - Group(1), Complete(0), date(2013-10-01)
Task #3 - Group(1), Complete(0), date(2013-12-01)
Task #2 - Group(false), Complete(0), date(2013-11-01)
Task #4 - Group(false), Complete(0), date(2013-12-01)
Task #1 - Group(false), Complete(1), date(2013-11-01)

即,如果组中的任务的日期早于单个任务,则应首先对整个组进行排序(想象一下,对于一个组,您只能看到"顶部"任务,因此任务#3将在视觉上折叠)。

我尝试更改"ORDER BY"子句的顺序,但似乎没有任何组合可以实现我所追求的 - 某些东西总是在错误的地方结束。

任何帮助非常感谢。

像这样的事情怎么样:

SELECT t1.ID, t1.`Group`, t1.Complete, t1.Due 
FROM task t1
LEFT JOIN (
    SELECT Complete, 
        t.`Group`, 
        MIN(Due) AS MinDate 
    FROM task t
    GROUP BY Complete, t.`Group` ) t2 ON t1.complete = t2.complete AND t1.`Group`  = t2.`Group`     
ORDER BY t1.complete, IFNULL(t2.MinDate, t1.Due), `Group`, t1.Due 
对于每个组记录,

将其连接到该组中最早的记录,然后您可以按最早的组日期排序(如果未分组,则仅按日期排序)。

SQLFiddle

所以你想按组中的最早日期排序,然后将整个组放在一起?

您可以使用 YourTable 上的聚合来获取每个组的最低日期。然后,您可以主要按该最小日期排序,然后按其他字段进行排序。

select
  t.id,
  t.group,
  t.date,
  t.complete
from
  YourTable t
  left join
    (select
      m.group,
      min(m.date) as mindate
    from
      YourTable m) mt on mt.group = t.group
order by
  /* Coalesce for individual tasks, which don't have a mindate */
  coalesce(mt.mindate, t.date),
  t.group,
  t.complete,
  t.date

然后,您可以开始尝试在该聚合中包含其他字段(如"完成")。例如,此查询应从包含未完成任务和未完成单个任务的组开始。之后是已完成的任务和仅包含已完成任务的组。在组中,仍然应用排序,将未完成的任务放在已完成任务的上方,然后按日期对它们进行排序。如您所见,许多额外的逻辑只对查询进行了很小的更改:

select
  t.id,
  t.group,
  t.date,
  t.complete
from
  YourTable t
  left join
    (select
      m.group,
      min(m.date) as mindate,
      min(m.complete) as groupcomplete
    from
      YourTable m) mt on mt.group = t.group
order by
  coalesce(mt.groupcomplete, t.complete),
  coalesce(mt.mindate, t.date),
  t.group,
  t.complete,
  t.date