Создание вложенной <ul>древовидной структуры из ParentID в БД - PullRequest
2 голосов
/ 12 июля 2011

Это кажется довольно распространенной задачей, которую я хочу выполнить, но я не могу обернуться вокруг cfloops и cfqueries.

У меня есть база данных, полная фотогалерей. Все они имеют ID и ParentID (кроме корневых галерей - их ParentID пуст), и они могут проходить несколько уровней. Вот пример структуры галереи:

  • 1
    • 1-1
    • 1-2
  • 2
    • 2-1
      • 2-1-1
      • 2-1-2

Я хочу автоматически выводить эту структуру выше во вложенные ul и li (как и выше). Как это сделать? Я не могу обернуть голову вокруг расположения ul и li для правильного отображения уровней иерархии.

Ответы [ 5 ]

1 голос
/ 13 июля 2011

Это смесь SQL и Coldfusion.Вероятно, не самый лучший формат для подписи в SQL Server, но он дает нужный формат.

SQL:

CREATE TABLE testTable(id int, parentID int)
INSERT INTO testTable(id, parentID) VALUES
    (1, NULL)
    , (2, 1)
    , (3, 1)
    , (4, NULL)
    , (5, 4)
    , (6, 5)
    , (7, 5)
    , (8, 4)

Coldfusion:

<cfscript>
    qs = new query();
    qs.setDatasource("datasource");
    qs.setSQL("
        ;WITH cte AS
        (
            SELECT t.ID, t.parentID, 1 AS level, 
                CAST(DENSE_RANK() OVER (PARTITION BY t.parentID ORDER BY t.ID) AS varchar(max)) AS label
            FROM testTable t
            WHERE parentID IS NULL

            UNION ALL 

            SELECT t.ID, t.parentID, cte.level + 1 AS level, 
                CAST(cte.label AS varchar(max)) + ' - ' + CAST(DENSE_RANK() OVER (PARTITION BY t.parentID ORDER BY t.ID) AS varchar(max)) AS label
            FROM testTable t
                INNER JOIN cte ON cte.ID = t.parentID
        )
        SELECT *,
            DENSE_RANK() OVER (PARTITION BY parentID ORDER BY ID) AS [order]
        FROM cte
        ORDER BY label
    ");
    qMenu = qs.execute().getResult();

    oldLevel = 0;

    for (i=1;i<=qMenu.recordCount;i++){        
        if (qMenu.level[i] > oldLevel) {
            WriteOutput("<ul>");
        }

        while (qMenu.level[i] < oldLevel) {
            WriteOutput("</ul>");
            oldLevel--;
        }

        WriteOutput("<li>" & qMenu.label[i] & "</li>");

        oldLevel = qMenu.level[i];

    }

    do {
        WriteOutput("</ul>");
        oldLevel--;
    } while (oldLevel > 0);
</cfscript>
1 голос
/ 12 июля 2011

Я бы использовал запрос запросов, чтобы сделать это рекурсивно.

Примечание: приведенный ниже код НЕ проверен, поэтому, пожалуйста, используйте в качестве примера psuedocode.

<cfquery query="qReadAllData">
  select * from your_table
</cfquery>

<!--- Read all roots (no parent ID) --->
<cfquery query="qReadRoots" dbtype="query">
  select nodeID from qReadAllData
  where parentID is null
</cfquery>

<ul>
  <cfloop query="qReadRoots">

    <cfset processNode(qReadRoots.nodeID) />

  </cfloop>
</ul>


<cffunction name="processNode" output="true">
  <cfargument name="nodeID" type="any" />

  <!--- Check for any nodes that have *this* node as a parent --->
  <cfquery query="LOCAL.qFindChildren" dbtype="query">
    select nodeID from qReadAllData
    where parentID = #ARGUMENTS.nodeID#
  </cfquery>

  <cfif LOCAL.qFindChildren.recordcount>

    <!--- We have another list! --->
    <li>
      <ul>
        <!--- We have children, so process these first --->
        <cfloop query="LOCAL.qFindChildren">

          <!--- Recursively call function --->
          <cfset processNode(LOCAL.qFindChildren.nodeID) />

        </cfloop>

      </ul>
    <li>


  <cfelse>

     <!--- We have no more children, so we just output the value --->
     <li>#nodeID#<li>

  </cfif>

</cffunction>

Уже поздно.Я устал.Я надеюсь, что это правильно :)

1 голос
/ 12 июля 2011

Полагаю, самым простым решением было бы использование Query of Query ...

Если набор данных огромен, попробуйте <cftree> и заполните листья по требованию.

0 голосов
/ 12 июля 2011

Итак, если вы дадите фактическую структуру данных, которую я изменю в соответствии с вашими фактическими полями:

Вы можете добавить столбец глубины и линии (fullPath) в свою таблицу, а затем простоодин простой выбор, чтобы получить иерархию и вывести ее соответственно.Выполнен один запрос.

WHILE EXISTS (SELECT * FROM Tree WHERE levelDeep Is Null) 
UPDATE T SET T.levelDeep = P.levelDeep + 1, 
T.fullPath= P.fullPath+ Ltrim(Str(T.ParentNode,6,0)) + '/' 
FROM Tree AS T 
INNER JOIN Tree AS P ON (T.ParentNode=P.Node) 
WHERE P.levelDeep >=0 
AND P.fullPathIs Not Null 
AND T.levelDeep Is Null
0 голосов
/ 12 июля 2011

Вот что вам нужно:

Хранимая процедура T-SQL для циклического выполнения иерархии с рекурсией

Дайте мне знать, если вам нужна помощь в реализации этой таблицы

Обновление: См новый ответ с запросом для обновления с глубиной для легкого выбора / вывода.

...