数据库有如下字段,这是你可以利用的所有辅助信息..Id(自增),Title,parentId(父接点),orderId(排序),ParentPath(所有父结点),depth(深度,从0开始,根结点是0),child(子结点数)
解释一下orderId.  orderId字段一定是按整数顺序排的,每一级有单独的排序.如果某级有8个子结点,这8个接点的排序一定是1-8,他父结点的Child是8. 
parentpath. 如果 4是2的孩子.2是1的孩子.那么4的parentPath就是0,1,2,4,(这里会包括自己)
说明一下要求.我先帮大家解释一下.
根接点前无任务符号.
第二级前面是1个符号. 这个结点前的符号究竟是  └  还是 ├ 这取决于他是不是最后一个结点是的话就是└ ,
第三级结点前有两个符号,第三个结点前是什么符号就复杂了.大家自己看吧.
其实就是不停的判断它的父接点来完成.这样要是在数据库里操作.太费资源了,不知道有没有好的算法啊.

解决方案 »

  1.   

    parentId(父接点),orderId(排序),ParentPath(所有父结点),depth(深度,从0开始,根结点是0),这几个东西都有了,就没什么好高效不高效的存储过程了。几个order by就解决了。跟dvbbs的版块无级分类结构一样
      

  2.   

    你可能跟本没看清问题.这跟本不是几个order by能解决的.关键是处理Title前面的符号.
      

  3.   

    child 子节点个数
    parentId 父节点id就这两个参数就足以处理title前的符号了.自己把自己表结构里的数据定义好好理理SELECT charBeforeTitle = 
             /*若是根*/
             CASE WHEN parentID IS NULL /*这里依具你的数据定义,根目级的父ID设置也可能是0*/ THEN '| '
             /*若非根,且有子项*/
             WHEN Child!=0 THEN REPLICATE('| ',depth-1) + 
                 /*若是同级最后一个*/
                 CASE WHEN NOT EXISTS(SELECT 1 FROM tb WHERE parendID=a.parendID AND orderid>a.orderID) THEN '|_'
                 /*若非同级最后一个*/
                      ELSE '|-' 
                 END
             /*若非根且无子项*/
             ELSE REPLICATE('| ',depth-1) + 
                 /*若是同级最后一个*/
                 CASE WHEN NOT EXISTS(SELECT 1 FROM tb WHERE parendID=a.parendID AND orderid>a.orderID) THEN '|_'
                 /*若非同级最后一个*/
                      ELSE '|-' 
                 END
             END ,
             *
          FROM tb ORDER BY .... /*具体怎么写,看你的参数定义*/
    我是随手敲的, 不排除手误,另外,输出的字符,我随便打了两个示下意,具体用什么你自己决定.由于只要不是根节点,它们的处理方式都一样,语句又可以简化为SELECT charBeforeTitle = 
             /*若是根*/
             CASE WHEN parentID IS NULL /*这里依具你的数据定义,根目级的父ID设置也可能是0*/ THEN '| '
             /*若非根*/
             ELSE REPLICATE('|',depth-1) + 
                 /*若是同级最后一个*/
                 CASE WHEN NOT EXISTS(SELECT 1 FROM tb WHERE parendID=a.parendID AND orderid>a.orderID) THEN '|_'
                 /*若非同级最后一个*/
                      ELSE '|-' 
                 END
             END ,
             *
          FROM tb ORDER BY .... /*具体怎么写,看你的参数定义*/
      

  4.   

    FROM tb a从性能和实现的方便角度考滤, 没有必要在sql里做这样的处理, order by 处理好排序之后, 在前端应用程序代码里处理前面字符的输出.
      

  5.   

    再给你一个刚写的xslt格式化xml输出类似于你要求的select option的例子.因为我的xml数据中,没有你那么多的字段值,所以跟你的要求有点区别.
    代码调用xsl模版递规实现.另外,从数据库来操作的话,因为你的数据不需要再做什么检索,所以数据库递规代码写了也就没意义了,我就不写了.
    test.xml<?xml version="1.0" encoding="utf-8" ?>
    <?xml-stylesheet type="text/xsl" href="test.xsl"?>
    <classes>
    <class id="2" pid="0" depth="0">MSSQL</class>
    <class id="3" pid="2" depth="1">T-SQL</class>
    <class id="4" pid="3" depth="2">树相关</class>
    <class id="5" pid="3" depth="2">行转列或列转行</class>
    <class id="6" pid="0" depth="0">WEB开发</class>
    <class id="7" pid="6" depth="1">Asp.Net</class>
    <class id="8" pid="6" depth="1">Xml.Xsl</class>
    <class id="9" pid="2" depth="2">备份恢复</class>
    <class id="10" pid="6" depth="1">Javascript</class>
    </classes>test.xsl
    <?xml version="1.0" encoding="utf-8"?>
    <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template match="/">
        <html>
          <head>
          </head>
          <body>
    <select>
              <xsl:apply-templates select="//class[@pid=0]"/>
    </select>
          </body>
        </html>
      </xsl:template>
      <xsl:template match="//class">
        <xsl:param name="id" select="@id"/>
        <xsl:param name="depth" select="@depth"/>
        <xsl:param name="name" select="."/>
        <option value="{$id}">
        <xsl:value-of select="substring('|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  ',1,$depth*3)" />
          <xsl:choose>
            <xsl:when test="count(//class[@pid=$id]) &gt; 0">
      |-
            </xsl:when>
            <xsl:otherwise> |-</xsl:otherwise>
          </xsl:choose>
          <xsl:value-of select="."/>
        </option>
         <xsl:apply-templates select="//class[@pid=$id]"/>
      </xsl:template>
    </xsl:transform>
      

  6.   

    多谢.不过这样不太对,可能你没注意到.并不是所有结点前面都有"|"有的前面是空格,
    比如:
    ││  └下学期 第三格是一个空格.因为下学期的父结点是平级结点的最后一个结点.所以为空格.而下学期父父的结点不是最后一个结点所以是│如果这个分类展开到最后你会发现下面不再有"│" 而全部被置换为空格.比如:
    ├AA
    └BB
      ├AA
      └BB
        ├AA
        └BB由此可以找出规律.前面的符号并不由自身结点决定,而是由他的父结点不停的递归得到.
    在阿信树的JS里,有一个递归来判断他的父结点.
    如果程序由服务端来执行,不论放在程序里还是在存储过程里.这样判断都是一个费资源的判定.fxNode.prototype.indent = function()
    {
    var s ="";
    if(this.parentNode!=null)
    s += (this.isLast ? "└ " : "├ ");
    var p = this.parentNode;
    while(p!=null)
    {
    if(!p.parentNode)break;
    s = (p.isLast ? "  " : "│")+s;
    p = p.parentNode;
    }
    return s;
    }