复杂的MySQL排序

时间:2017-01-12 18:22:33

标签: 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成为&#34;群组标题&#34;按ord排序。然后在每个行的下方,我需要对行进行排序,使得id2等于其上方行的id1,并且任何时候id2都与{{1}相同对于它上面的行,它应该按id2排序。

如果ord与上一个id2匹配的行数不足,则应显示下一个组标题,并且应在下一个id1匹配{{1}时重新开始排序新组标题。

id2为空的任何项都是一个组标题,但在这些组中,id1根据&#34; parent&#34;重新开始。线。其中一些行也是其他项目的父项,因此排序的复杂性

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

解释表数据

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

ord是主键且唯一,与排序顺序无关,除了JOIN等于给定id1组标题的所有行都应该出现在它下面。 id2是对&#34;父线ID&#34;的引用。因此,为什么它对于组头是空的;他们是最父级的行,并通过id1拥有自己的排序顺序。 id2实际上是组标题行所期望的项目名称。

例如,假设群组标题是食物组,其他条目是食物类型。因此,一个组头将是#34; fruit,&#34;下一个&#34;蔬菜,&#34;它实际上是A / V装备,但水果可能更容易理解。

我做了什么

我对此的尝试已遍布整个地图。我已经尝试了各种ordnameorder by,并且我已经考虑了子查询,但我的技能不仅仅是在我的拥有。我想如果我能指出正确的方向,我可以把我所拥有的东西结合起来得到正确的结果。不幸的是,出于沮丧,我删除了任何半工作代码,但它可能只是一个field()带有不起作用的if()语句。

要点:

  1. ORDER BY为空时,它是一个组标题,组标题应按其CASE字段从最低到最高(0,1,2)排序。
  2. id2等于另一行&#39; s ord的任何行都是其父级。换句话说,如果找到一行id1等于另一行的id2,则应将其置于其下方。
  3. 如果存在多个行id2等于id1,则排序应首先考虑#2,然后按id2排序从最低到最高。

2 个答案:

答案 0 :(得分:1)

您描绘的数据是层次结构(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

答案 1 :(得分:1)

已经有一段时间了。老实说,我已经忘记了它代表的意思,但是我相信我试图对订单项在应用程序中的显示进行排序。假设情况如此,我从一位开发人员那里得到了答案。我们最终使用了COALESCE()LPAD()的组合。

说这些是列表中的订单项,但有些是嵌套的,它们都位于同一表中。唯一的关系是知道父行的idordinal。我们想到了这个:

SELECT CONCAT_WS('-', LPAD(COALESCE(item5.ordinal),4,'0'),`
   LPAD(COALESCE(item4.ordinal),4,'0'),
   LPAD(COALESCE(item3.ordinal),4,'0'),
   LPAD(COALESCE(item2.ordinal),4,'0'),
   LPAD(COALESCE(item.ordinal),4,'0')) AS line_order
FROM main_lines as main
LEFT JOIN sub_line as item on item.id = main.id
LEFT JOIN sub_line as item2 on item2.id = item.parent_line_id
LEFT JOIN sub_line as item3 on item3.id = item2.parent_line_id
LEFT JOIN sub_line as item4 on item4.id = item3.parent_line_id
LEFT JOIN sub_line as item5 on item5.id = item4.parent_line_id

ORDER BY line_order;

COALESCE允许我们对行进行空安全保护,而LPAD则允许CONCAT_WS提供正确的排序顺序,并在每个结果中使用0。