mysql - 复杂的 MySQL 排序

标签 mysql sorting

我几乎完全重写了这个问题,因为我仍然卡住了......寻找一种方法来查看结果表中的数据,而不必使用 php 或其他一些数据解释器/编程来以我希望的方式查看结果。

基本结果表是这样的(如果你愿意,可以把它弄得更乱):

 id1 |  id2 | name   | ord
 ------------------------------
 a1  | null | name1  |  0
 a2  | null | name2  |  1
 a3  | null | name3  |  2
 b1  |  a1  | name4  |  0
 b2  |  b1  | name5  |  0
 b3  |  a1  | name6  |  1
 b4  |  a1  | name7  |  2
 c1  |  a2  | name8  |  0
 c2  |  a2  | name9  |  1
 d1  |  a2  | name10 |  2
 d2  |  a2  | name11 |  3
 d3  |  a2  | name12 |  4
 d4  |  a3  | name13 |  0
 c3  |  d4  | name14 |  0
 c4  |  c3  | name15 |  1
 d5  |  b2  | name16 |  0

我要找的结果是这样的:

 id1 |  id2 | name   | ord
 -----------------------------
 a1  | null | name1  |  0  <--group header, signified by `id2` is null
 b1  |  a1  | name4  |  0  <--item that's parent to line below
 b2  |  b1  | name5  |  0  <--item that's parent to line below
 d5  |  b2  | name16 |  0  <--last child item
 b3  |  a1  | name6  |  1  <--special case where `ord` takes over
 b4  |  a1  | name7  |  2  <--`id2` is still the same, so `ord` sort
 a2  | null | name2  |  1  <--next group header
 c1  |  a2  | name8  |  0  <--`id2` is a2, so name2 is parent, `ord` sort
 c2  |  a2  | name9  |  1  <--same
 d1  |  a2  | name10 |  2  <--same
 d2  |  a2  | name11 |  3  <--same
 d3  |  a2  | name12 |  4  <--same
 a3  | null | name3  |  2  <--next group header
 d4  |  a3  | name13 |  0  <--`id2` is a3, so name3 is parent
 c3  |  d4  | name14 |  0  <--`id2` is d3, so name13 is parent
 c4  |  c3  | name15 |  1  <--`id2` is c3, so name14 is parent

文字说明我需要什么

本质上,我需要 id2 成为按 ord 排序的“组 header ”。然后在它们每个下面,我需要以 id2 等于它上面一行的 id1 以及任何时候 id2 的方式对行进行排序> 与它上面一行的 id2 相同,它应该按 ord 排序。

id2 与最后一个 id1 匹配的行用完时,应该出现下一个组标题,并且应该从下一个 id2 重新开始排序 匹配新组头的 id1

id2 为 null 的任何项目都是组标题,但在这些组中,ord 基于“父”行重新开始。其中一些行也是其他项目的父级,因此排序的复杂性

实际结果表中还有其他列,因此我将其简化为实际进行排序所需的列。

表格数据解释

实际的 id 列是 char(36),name 是 varchar(1024),ord 是 int(11),而表中的其他列运行色域...我还应该提到,这些结果来自 JOIN,这样做是为了限制找到该数据的主表的结果。

id1 是主键并且是唯一的,与排序顺序无关,除了具有 id2 的所有行等于给定的 id1 组标题应该出现在它下面。 id2 是对“parent line id”的引用,因此它对于组标题为空;它们是最父级的行,并且通过 ord 有自己的排序顺序。 name 实际上是组标题行的项目名称,它们是类别名称。

例如,假设组标题是食物组,而其中的其他条目是食物类型。因此,一个组标题将是“水果”,下一个是“蔬菜”等。它实际上是 A/V 设备,但水果可能更容易理解。

我做了什么

我在这方面的尝试无处不在。我尝试了各种order byfield()if(),我也考虑过子查询,但我的技能还不够最多我自己解决这个问题。我认为,如果我能指出正确的方向,我就可以结合我所拥有的来获得正确的结果。不幸的是,出于沮丧,我删除了所有半工作代码,但它可能只不过是一个带有非工作 CASE 语句的 ORDER BY

要点:

  1. id2 为 null 时,它是一个组 header ,并且组 header 应按其 ord 字段从低到高(0、1、2)排序。
  2. id1 等于另一行的 id2 的任何行都是其父行。换句话说,如果发现一行的 id2 等于另一行的 id1,则应将其放在下面。
  3. 如果存在多个行,其中 id2 等于 id1,则排序应首先考虑 #2,然后按 ord 从低到高排序.

最佳答案

您描述的数据是分层的(id2 指的是“父级”)并且在 MySQL 中(至少 5.7)没有特定的功能,例如递归 CTE 来处理层次结构。有变通办法,在这里,我们似乎知道我们可以为每个(级别 - 1)使用一个左连接的最大级别数(即,对于 4 个级别,添加 3 个左连接)。一旦通过连接建立了层次结构,然后在各个列中使用 COALESCE(),由于左连接,其中许多列现在可以为 NULL,我们可以安排数据以适合所需的排序顺序。 (好吧,“差不多”。如果您将想要的订单与下面查询显示的订单进行比较,就会发现一些细微差别。)

请引用这个SQL Fiddle还有。

CREATE TABLE Table1
    (`id1` varchar(2), `id2` varchar(4), `name` varchar(6), `ord` int)
;

INSERT INTO Table1
    (`id1`, `id2`, `name`, `ord`)
VALUES
    ('a1', NULL, 'name1', 0),
    ('a2', NULL, 'name2', 1),
    ('a3', NULL, 'name3', 2),
    ('b1', 'a1', 'name4', 0),
    ('b2', 'b1', 'name5', 0),
    ('b3', 'a1', 'name6', 1),
    ('b4', 'a1', 'name7', 2),
    ('c1', 'a2', 'name8', 0),
    ('c2', 'a2', 'name9', 1),
    ('d1', 'a2', 'name10', 2),
    ('d2', 'a2', 'name11', 3),
    ('d3', 'a2', 'name12', 4),
    ('d4', 'a3', 'name13', 0),
    ('c3', 'd4', 'name14', 0),
    ('c4', 'c3', 'name15', 1),
    ('d5', 'b2', 'name16', 0)
;

查询:

select
      coalesce(p1.id1, p2.id1, p3.id1, p4.id1) id1s
    , coalesce(p1.id2, p2.id2, p3.id2, p4.id2) id2s
    , coalesce(p1.name, p2.name, p3.name, p4.name) names
    , coalesce(p1.ord, p2.ord, p3.ord, p4.ord) ords
    #, coalesce(p4.id1, p3.id1, p2.id1, p1.id1) ord1
    #, coalesce(p4.id2, p3.id2, p2.id2, p1.id2) ord2
    #, coalesce(p4.ord, p3.ord, p2.ord, p1.ord) ord3
from        table1 p1
left join   table1 p2 on p1.id2 = p2.id1
left join   table1 p3 on p2.id2 = p3.id1 
left join   table1 p4 on p3.id2 = p4.id1 
order by
      coalesce(p4.id1, p3.id1, p2.id1, p1.id1)
    , coalesce(p4.id2, p3.id2, p2.id2, p1.id2)
    , coalesce(p4.ord, p3.ord, p2.ord, p1.ord)
    , id2s

Result :

| id1s |   id2s |  names | ords |
|------|--------|--------|------|
|   a1 | (null) |  name1 |    0 |
|   b3 |     a1 |  name6 |    1 |
|   b4 |     a1 |  name7 |    2 |
|   b1 |     a1 |  name4 |    0 |
|   b2 |     b1 |  name5 |    0 |
|   d5 |     b2 | name16 |    0 |
|   a2 | (null) |  name2 |    1 |
|   d3 |     a2 | name12 |    4 |
|   c2 |     a2 |  name9 |    1 |
|   d1 |     a2 | name10 |    2 |
|   d2 |     a2 | name11 |    3 |
|   c1 |     a2 |  name8 |    0 |
|   a3 | (null) |  name3 |    2 |
|   d4 |     a3 | name13 |    0 |
|   c4 |     c3 | name15 |    1 |
|   c3 |     d4 | name14 |    0 |

想要:

# id1 |  id2 | name   | ord
# -----------------------------
# a1  | null | name1  |  0  <--group header, signified by `id2` is null
# b1  |  a1  | name4  |  0  <--item that's parent to line below
# b2  |  b1  | name5  |  0  <--item that's parent to line below
# d5  |  b2  | name16 |  0  <--last child item
# b3  |  a1  | name6  |  1  <--special case where `ord` takes over
# b4  |  a1  | name7  |  2  <--`id2` is still the same, so `ord` sort
# a2  | null | name2  |  1  <--next group header
# c1  |  a2  | name8  |  0  <--`id2` is a2, so name2 is parent, `ord` sort
# c2  |  a2  | name9  |  1  <--same
# d1  |  a2  | name10 |  2  <--same
# d2  |  a2  | name11 |  3  <--same
# d3  |  a2  | name12 |  4  <--same
# a3  | null | name3  |  2  <--next group header
# d4  |  a3  | name13 |  0  <--`id2` is a3, so name3 is parent
# c3  |  d4  | name14 |  0  <--`id2` is d3, so name13 is parent
# c4  |  c3  | name15 |  1  <--`id2` is c3, so name14 is parent

关于mysql - 复杂的 MySQL 排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41620300/

相关文章:

mysql - 用户存在和不存在查询

arrays - 如何根据列中的特定值从数组中挑选出行?

c - 尝试运行一个排序 C 程序,该程序通过命令行(Mac 终端)接收输入

java - 使用 Java 对数百万个 int/string 对进行排序

php/mysql 计算匹配条件的项目数

mysql - 如何使用 cron 启动 mysql

MySQL:查询本周数据

Java根据另一个数组对多个数组进行排序

sql-server - Excel 和 SQL 排序之间的差异

mysql - 如何解决错误 1396 (HY000) : Operation ALTER USER failed for 'root' @'localhost' ?