MySQL按层次结构排序

时间:2015-06-10 22:52:31

标签: mysql sorting hierarchy

我问了这个问题previously,但这是一个双层树,我得到的解决方案完美无缺。

我现在有一个多级树(最多3个,但我们假设将来会有更多。

我的代码目前看起来像这样:

SELECT * FROM fin_document AS finl

LEFT OUTER JOIN fin_document AS finl2
ON finl2.id = finl.parent_line_id

ORDER BY
CASE WHEN finl2.ordinal IS NULL THEN finl.ordinal
ELSE concat(finl2.ordinal,'-',finl.ordinal) END

让我们假设一个与以前类似的树:

(id)  (Item)    (#)  (parent_line_id)
1234 - Car    -  1 -  null
0000 - Boat   -  2 -  null
2222 - House  -  4 -  null
6545 - Bike   -  5 -  null
6547 - Wheels -  0 -  1234
4442 - Bed    -  1 -  2222
1474 - Sink   -  0 -  2222
9456 - Tires  -  0 -  6547                  *New item, child of wheels
8975 - L.Nuts -  1 -  6547                  *New item, child of wheels

哦,#列是"序数"

那么如何让这个与多个父母一起排序?

正确的排序应如下所示:

(id)  (Item)    (#)  (parent_line_id)
1234 - Car    -  1 -  null
6547 - Wheels -  0 -  1234
9456 - Tires  -  0 -  6547
8975 - L.Nuts -  1 -  6547 
0000 - Boat   -  2 -  null
2222 - House  -  4 -  null
1474 - Sink   -  0 -  2222
4442 - Bed    -  1 -  2222
6545 - Bike   -  5 -  null

注意:我不能改变任何表格。我只能从表中提取数据,因为表是由另一家公司管理的,我们使用的软件是谁。我知道如果有更多的孩子,他们会变得越来越复杂,但我认为我的公司将使用这个孩子的人数不会超过3-4个。不幸的是,由于这种复杂性,这就是为什么我不得不回到这里并再次询问:(

3 个答案:

答案 0 :(得分:1)

希望您不会在没有修改的情况下寻找适合N深层次结构的东西。

然而,这应该是相当简单的。

SELECT id,
    item,
    o,
    parent_line_id
FROM (
    SELECT *,
        1 AS parentage,
        o AS rank
    FROM table1
    WHERE parent_line_id IS NULL

    UNION ALL

    SELECT t2.id,
        t1.item,
        t1.o,
        t1.parent_line_id,
        2 AS parentage,
        t2.o AS rank
    FROM table1 t1
    INNER JOIN table1 t2 ON t1.parent_line_id = t2.id
        AND t2.parent_line_id IS NULL

    UNION ALL

    SELECT t3.id,
        t1.item,
        t1.o,
        t1.parent_line_id,
        3 AS parentage,
        t3.o AS rank
    FROM table1 t1
    INNER JOIN table1 t2 ON t1.parent_line_id = t2.id
        AND t2.parent_line_id IS NOT NULL
    INNER JOIN table1 t3 ON t2.parent_line_id = t3.id
    ) q
ORDER BY rank ASC,
    parentage ASC,
    o ASC;

demo here

基本前提是我们识别所有无父项目,并为其提供1的父母身份。

然后我们确定他们的孩子,给他们2的父母,他们的孩子得到3的父母。

然后,所有这些都继承了第一个父母序号以进行分类。

可能有其他方法可以做到这一点,我甚至可能会去寻找它们,但同时也是如此 - 这很有效。

答案 1 :(得分:0)

这里有dirty trick来处理任意深度:

SELECT a.k, b.*
FROM (
    SELECT a.id, a.k
    FROM (
        SELECT CONCAT(LEFT(
               (@c := @previous_id <> b.id OR @previous_id IS NULL)
               & (@id := IF( @c, b.id, (SELECT parent_line_id FROM fin_document WHERE id = @id)))
               & (@num := LPAD(IF( @c, b.num, (SELECT num FROM fin_document WHERE id = @id)), 5, ' '))
               & (@key := IF( @c, @num, CONCAT(@num, '', @key) ))
               & (@previous_id := b.id),0),@key) k,
               b.id
        FROM fin_document a
        STRAIGHT_JOIN ( SELECT @previous_id := NULL, id, num FROM fin_document ) b ) a
            WHERE k IS NOT NULL
    ORDER BY id, LENGTH(k) DESC) a
JOIN fin_document b ON a.id = b.id
GROUP BY a.id
ORDER BY k;

fiddle(不确定为什么列k没有正确显示。列k表示排序键,并且使用与原始查询类似的格式构建) 此外,它需要指数执行时间。所以它可能不是你想要的。

答案 2 :(得分:0)

**

邻接表(层次结构)-基于级别的排序/顺序

**

对于正在搜索的任何人,如果您具有邻接列表ID->父结构,则实际上可以使用路径枚举模型来维护基于级别的排序:)

在“数据”表中,您将具有父级和一个排序值列

enter image description here

为了生成具有正确排序的层次结构,我使用以下CTE:

CTE_Topic_Details AS
(
SELECT Topic_id, CONVERT(Topic_id, CHAR(100)) as path, Topic_name as TopFullN,CONVERT(Topic_sort, CHAR(100)) as SortGPS
FROM topic
WHERE Topic_Topic_id IS NULL
UNION ALL
SELECT e.Topic_id, CONCAT(d.path, ".", CONVERT(e.Topic_id, CHAR(20))),  CONCAT(d.TopFullN, ">", e.Topic_name), CONCAT(d.SortGPS, ".", CONVERT(e.Topic_sort, CHAR(20)))
FROM topic e
JOIN CTE_Topic_Details d ON e.Topic_Topic_id = d.Topic_id
)

enter image description here

很好,不是吗!