【问题标题】:Convert a standard Mysql table to a nested table将标准 Mysql 表转换为嵌套表
【发布时间】:2011-05-15 15:18:19
【问题描述】:

像这样转换 MySQL 表的最干净的方法是什么:

     id | fullindi                              | parent | rank
---------------------------------------------------------------
      1 | LHUILLIER Pierre (ca 1700 - 1745)     |    0   |   0
      9 | LHUILLIER Claude (ca 1729 - 1806)     |    1   |   1
  10357 | LHUILLIER Joseph (ca 1730 - 1738)     |    1   |   2
      7 | LHUILLIER François (ca 1731 - 1794)   |    1   |   3
      3 | LHUILLIER Antoine (1736 - av. 1797)   |    1   |   4
      4 | LHUILLIER Anne Marie (1737 - ____)    |    1   |   5
   4903 | LHUILLIER Dominique (1740 - ____)     |    1   |   6
      5 | LHUILLIER Thérèse (1741 - ____)       |    1   |   7
      8 | LHUILLIER Augustin (ca 1743 - ____)   |    1   |   8
      6 | LHUILLIER Joseph (1745 - ap. 1804)    |    1   |   9
    322 | LHUILLIER N... (1749 - ____)          |    9   |   1
    323 | LHUILLIER Marianne (1751 - ____)      |    9   |   2
    324 | LHUILLIER François (1752 - ____)      |    9   |   3
    325 | LHUILLIER Augustin (1754 - av. 1810)  |    9   |   4
    326 | LHUILLIER Léopold (1757 - av. 1819)   |    9   |   5
    327 | LHUILLIER Nicolas (1758 - ____)       |    9   |   6
    328 | LHUILLIER N... (1760 - ____)          |    9   |   7
    329 | LHUILLIER Claude (1765 - ____)        |    9   |   8
   4643 | LHUILLIER Jean Baptiste (1766 - 1836) |    9   |   9
    331 | LHUILLIER Marie Jeanne (1767 - 1823)  |    9   |  10
   etc

到这样的嵌套表:

     id | fullindi                              | posleft | posright
--------------------------------------------------------------------
      1 | LHUILLIER Pierre (ca 1700 - 1745)     |    0    |   848
      9 | LHUILLIER Claude (ca 1729 - 1806)     |    1    |   1
    322 | LHUILLIER N... (1749 - ____)          |    2    |   3
    323 | LHUILLIER Marianne (1751 - ____)      |    4    |   5
    324 | LHUILLIER François (1752 - ____)      |    6    |   7
    325 | LHUILLIER Augustin (1754 - av. 1810)  |    8    |   9
   etc

我确切地说它需要独立于深度(最大 = 20 个级别)和项目数量(超过 1.000 个项目)。

任何帮助将不胜感激。

最好的问候。

【问题讨论】:

    标签: mysql nested-table


    【解决方案1】:

    之前有个问题Here

    如果有人在 php 中执行此操作,您可能可以从中获取逻辑以获得所需的解决方案。

    我在一个糟糕的网站上发现了这个,而且 SQL 都在一行中,所以它需要一些格式。我几乎原样留下了示例,所有的功劳都应该归功于出色的 Joe Celko,他多年来一直在撰写有关 sql 的文章。

         CREATE TABLE Tree (
        child CHAR(10) NOT NULL, 
        parent CHAR(10), 
        CONSTRAINT PK_Tree PRIMARY KEY CLUSTERED(child))
    
         -- insert the sample data for testing 
    
         INSERT INTO Tree(child,parent) VALUES ('Albert', NULL)
         INSERT INTO Tree(child,parent) VALUES ('Bert', 'Albert') 
         INSERT INTO Tree(child,parent) VALUES ('Chuck', 'Albert') 
         INSERT INTO Tree(child,parent) VALUES ('Donna', 'Chuck') 
         INSERT INTO Tree(child,parent) VALUES ('Eddie', 'Chuck') 
         INSERT INTO Tree(child,parent) VALUES ('Fred', 'Chuck') 
    
    
    CREATE TABLE Stack (
        StackID int IDENTITY(1,1),
        stack_top INTEGER NOT NULL, 
        child VARCHAR(10) NOT NULL, 
        lft INTEGER NOT NULL, 
        rgt INTEGER, 
        CONSTRAINT PK_Stack PRIMARY KEY CLUSTERED(StackID))
    
    
        DECLARE @lft_rgt INTEGER, @stack_pointer INTEGER, @max_lft_rgt INTEGER
    
        SET @max_lft_rgt = 2 * (SELECT COUNT(*) FROM Tree)
    
        INSERT INTO Stack 
        SELECT 1, child, 1, @max_lft_rgt 
        FROM Tree 
        WHERE parent IS NULL
    
        SET @lft_rgt = 2
    
        SET @Stack_pointer = 1
    
        DELETE FROM Tree WHERE parent IS NULL
    
        -- The Stack is now loaded and ready to use 
    
        WHILE (@lft_rgt < @max_lft_rgt) 
            BEGIN 
                IF EXISTS (SELECT * FROM Stack AS S1, Tree AS T1 WHERE S1.child = T1.parent AND S1.stack_top = @stack_pointer) 
                    BEGIN 
                        -- push when stack_top has subordinates and set lft value 
                        INSERT INTO Stack 
                        SELECT (@stack_pointer + 1), 
                        MIN(T1.child), 
                        @lft_rgt, 
                        NULL 
                        FROM Stack AS S1, 
                        Tree AS T1 
                        WHERE S1.child = T1.parent AND S1.stack_top = @stack_pointer
    
                         -- remove this row from Tree 
                         DELETE FROM Tree 
                         WHERE child = (SELECT child FROM Stack WHERE stack_top = @stack_pointer + 1)
    
                         SET @stack_pointer = @stack_pointer + 1 
                    END 
            -- push 
            ELSE 
                BEGIN 
                    -- pop the Stack and set rgt value 
                    UPDATE Stack SET rgt = @lft_rgt, stack_top = -stack_top 
                    WHERE stack_top = @stack_pointer 
    
                    SET @stack_pointer = @stack_pointer - 1
                END
    
                -- pop 
            SET @lft_rgt = @lft_rgt + 1
        END
    

    您应该能够通过更改列名等来使用它来整理您的列表。

    再一次,这不是我的工作,再次感谢 Joe Celko(我很长时间以来一直是嵌套集合模型的粉丝,并且有一些生产系统正在使用它)。如果有,我一直找不到 Joe 的博客(如果您在外面,请在此处发表评论并获得所有功劳。

    【讨论】:

    • 我知道这篇文章,我花了一整天的时间试图适应它,但没有成功。它开始了工作,但无缘无故忘记了我的大部分条目,也没有任何错误消息。
    • 等一下,我在 t-sql 中找到了更好的方法。但是,我只能在一个蹩脚的网站上找到它,它给了我大量的 SQL,但都在一条线上。我现在已经格式化了,但需要测试一下。
    • 我坚持。我补充说它是为了创建一个家谱树,如果我有重复的条目(这在家谱中是可能的),你提到的帖子的代码就会崩溃并给出一个严重的错误。但是,左边的数字从“4”开始(而不是“0”或“1”),树的前两个人不在生成的嵌套表中......还有许多“未定义索引”通知,其中索引存在。
    • 非常感谢您的帮助!我今晚会试一试,但顺便说一句,它似乎很清楚。对于 Joe 的博客,所有链接都已失效……我相信如果让他对嵌套表主题有很好的看法,可能会很有用。再次感谢。
    • 我找到了 Joe Celko 的新博客:joecelkothesqlapprentice.blogspot.com 玩得开心!
    猜你喜欢
    • 2015-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-17
    • 2020-09-03
    • 1970-01-01
    • 2017-12-15
    • 2018-11-12
    相关资源
    最近更新 更多