Hey Guys,
Hope you can help me out over here. We are building a datamart for a large group of users. They will use BOE webi's to generate reports with. One of the tables is a category structure (see picture below).The strongest requirement is that they will be able to aggregate information on any level -including -all- sublevels.
For that to work, we need to write a recursive query that outputs all categories and all of their children (and grandchildren). So per "branch" if you will. I knew how to write that recursion in .Net but not how to do it in SQL. Before SQLUSA& Ramireddy's repsonses I had no clue how to implement that with CTE. -So thanks you guys!
I've added my solution below. The problem i am running into now is the maxrecursion. When using the CTE query below on the actual database it runs into the limitation of 32767 iterations. Anyone who can help me solve this, using the example below?
| |
![]() | ![]() |
Sample Table SQL
If exists (select top 1 * from sysobjects where xtype='U' and name = 'Category')
Drop Table Category
Go
Create Table Category(
CategoryId Numeric(18,0) Null,
ParentCategoryId Numeric(18,0) Null,
)
Go
Insert into Category(CategoryId,ParentCategoryId) Values (1,0)
Insert into Category(CategoryId,ParentCategoryId) Values (2,1)
Insert into Category(CategoryId,ParentCategoryId) Values (3,2)
Insert into Category(CategoryId,ParentCategoryId) Values (4,3)
Insert into Category(CategoryId,ParentCategoryId) Values (5,3)
Insert into Category(CategoryId,ParentCategoryId) Values (6,3)
Insert into Category(CategoryId,ParentCategoryId) Values (7,6)
Insert into Category(CategoryId,ParentCategoryId) Values (8,6)
Insert into Category(CategoryId,ParentCategoryId) Values (9,8)
Insert into Category(CategoryId,ParentCategoryId) Values (10,8)
Module Module1
Private cn As OleDb.OleDbConnection
Sub Main()
Try
cn = New OleDb.OleDbConnection("Provider=SQLNCLI.1;Password=MyPassword;Persist Security Info=True;User ID=MyUserAccount;Data Source=Localhost")
CreateTable()
If cn.State <> ConnectionState.Open Then
cn.Open()
End If
Dim SQL As New OleDb.OleDbCommand("SELECT CategoryId FROM Category", cn)
Dim Da As New OleDb.OleDbDataAdapter(SQL)
Dim Dt As New DataTable("Category")
Da.Fill(Dt)
For Each Dr As DataRow In Dt.Rows
AddKids(Dr(0), Dr(0))
Next
Catch ex As Exception
Console.WriteLine("Fatal Error")
End Try
End Sub
Private Sub CreateTable()
Try
If cn.State <> ConnectionState.Open Then
cn.Open()
End If
Dim sql As New OleDb.OleDbCommand("", cn)
sql.CommandText = "IF EXISTS (SELECT Top 1 * FROM Sysobjects where xtype='U' AND [Name] = 'CategoryRecursive') DROP TABLE CategoryRecursive;"
sql.ExecuteNonQuery()
sql.CommandText = "CREATE TABLE CategoryRecursive (ParentCategoryId varchar(50) Null, ChildCategoryId varchar(50) Null);"
sql.ExecuteNonQuery()
Catch ex As Exception
Console.WriteLine("Error Creating Table")
End Try
End Sub
Private Sub AddKids(ByVal Node As String, ByVal ParentNode As String)
Try
If cn.State <> ConnectionState.Open Then
cn.Open()
End If
Dim SQL As New OleDb.OleDbCommand("", cn)
If Len(Node) = 0 Then
SQL.CommandText = "SELECT CategoryId FROM Category WHERE ParentCategoryId is Null"
Else
SQL.CommandText = "SELECT CategoryId FROM Category WHERE ParentCategoryId = '" & Node & "'"
End If
Dim Da As New OleDb.OleDbDataAdapter(SQL)
Dim Dt As New DataTable("Category")
Da.Fill(Dt)
For Each Dr As DataRow In Dt.Rows
SQL.CommandText = "INSERT INTO CategoryRecursive (ParentCategoryId, ChildCategoryId) VALUES ('" & ParentNode & "','" & Dr(0).ToString & "')"
SQL.ExecuteNonQuery()
Call AddKids(Dr(0).ToString, ParentNode)
Next
Catch ex As Exception
Console.WriteLine("Error finding Kids")
End Try
End Sub
End Module
WITH CategoryRecursive AS
(
SELECT CategoryId, ParentCategoryId
FROM Category
UNION ALL
SELECT CR.CategoryId, C.ParentCategoryId
FROM Category AS C INNER JOIN CategoryRecursive AS CR
ON C.CategoryId = CR.ParentCategoryId
)
SELECT * FROM CategoryRecursive AS CR2
ORDER BY CR2.ParentCategoryId, CR2.CategoryId
John