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

时间:2013-11-11 13:13:00

标签: php mysql codeigniter

我有一组需要同时以多种方式订购的数据。

简化后,该表可以概括为:

任务

  • ID
  • group(int)
  • 日期(日期)
  • 完成(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'子句的顺序,但似乎任何组合都没有达到我所追求的目标 - 某些东西总是在错误的地方结束。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

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

您可以在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

答案 1 :(得分:1)

如下:

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