Solved

Recursive Function to Retrieve Hierarchical DB Data

Posted on 2007-03-22
8
874 Views
Last Modified: 2012-08-14
So, I'm developing a shopping cart system in ASP/JetSQL/Access right now... I've decided I want each product /categoryto be able to exist in as many categories as it wants, and have as many subcategories as it wants.  To do that, I've developed two tables in my DB, tblCategories and tblProducts, with this structure:

tblProducts
    ProdID   AUTOINCREMENT
    Name    TEXT
    Image    TEXT
    Price     CURRENCY
    UOM     TEXT

tblCategories
    CatID    AUTOINCREMENT
    Name    TEXT
    Link       TEXT
    Type     TEXT

Building a list of what categories a given product in is where the problem is.  I've read a ton of articles about storing hierarchical data in a DB, and because of the constraints of my software, I think my best bet is the recursive function (I won't have any trees much larger than 5 items anyway).  If you can suggest a way to implement one of the other strategies effectively, please, do.

Now, in the recursive function I'm running into two issues, one of which I have a workaround for.  The first is, the function is supposed to return an array with the paths to each parent... it gives me a type mismatch when I do it that way, so I've used the Join() and Split() functions as a workaround.  If you have a better solution, please share!

The REAL issue that's causing me grief is... the function reports the wrong data!  When I run my queries, I get bogus data back from the server.  Here's my function:

Function getCatList(qType, product)
      Dim result: result = ""                  'Final String value returned
      Dim results()                              'Array containing result strings; returned from qType=1
      Dim tmpRslt                                    'Array containing response from recursion
      
      If qType = 0 Then
            Dim rsProduct
            Set rsProduct = Server.CreateObject("ADODB.Recordset")
            With rsProduct
                  .ActiveConnection = clntDSN
                  .Source = "SELECT Link FROM tblCategories WHERE Type='Product' AND Name='" & product & "'"
                  .CursorLocation = 2
                  .CursorType = 0
                  .LockType = 1
                  .Open()
            End With

            If rsProduct.EOF Or rsProduct.BOF Then
                  'Product does not exist
                  result = "<a href=""help.asp?q=noprod"">Product Not Found</a>"
            Else
                  While Not rsProduct.EOF And Not rsProduct.BOF
                        tmpRslt = Split(getCatList(1, rsProduct.Fields.Item("Link").Value), "\\""//")
                        
                        If tmpRslt(0) = "NS_DNE" Then
                              'Category does not exist
                              result = result & "<a href=""help.asp?q=nocat"">Category Not Found</a> -> " & product & "<br>" & vbCrLf
                        Else                        
                              For i=0 To UBound(tmpRslt)
                                    result = result & tmpRslt(i) & " -> " & product & "<br>" & vbCrLf
                              Next
                        End If
                        
                        rsProducts.MoveNext
                  WEnd
            
                  rsProduct.Close()
                  Set rsProduct = Nothing
                  
                  getCatList = result
            End If 'Product Exists
      End If 'Product Query

      Dim rsCategories
      Set rsCategories = Server.CreateObject("ADODB.Recordset")
      With rsCategories
            .ActiveConnection = clntDSN
            .Source = "SELECT Link FROM tblCategories WHERE Type='Parent' AND Name='" & product & "'"
            .CursorLocation = 2
            .CursorType = 0
            .LockType = 1
            .Open()
      End With
      
      Dim rsCount
      Set rsCount = Server.CreateObject("ADODB.Recordset")
      With rsCount
            .ActiveConnection = clntDSN
            .Source = "SELECT COUNT(Link) AS recs FROM tblCategories WHERE Type='Parent' AND Name='" & product & "'"
            .CursorLocation = 2
            .CursorType = 0
            .LockType = 1
            .Open()
      End With
      
      If rsCategories.BOF Or rsCategories.EOF Then
            ReDim results(1)
            results(0) = "NS_DNE"
      ElseIf rsCategories.Fields.Item("Link").Value = "NS_TOP_LEVEL" Then
            ReDim results(1)
            results(0) = "NS_TOP_LEVEL"
      Else
            Dim rec: rec = 0
            Dim recs: recs = CInt(rsCount.Fields.Item("recs").Value)
            ReDim results(recs)
            
            While Not rsCategories.BOF And Not rsCategories.EOF
                  tmpRslt = Split(getCatList(1, rsCategories.Fields.Item("Link").Value), "\\""//")
                  If tmpRslt(0) = "NS_TOP_LEVEL" Then
                        'Add this link, but not it's parent (it doesn't have one)
                        results(rec) = "<a href=""store.asp?category=" & product & """>" & product & "</a> -> "
                  ElseIf tmpRslt(0) = "NS_DNE" Then
                        'Category does not exist
                        results(rec) = "Category Not Found -> " & product
                  Else
                        'Add this link and it's parents
                        recs = recs + UBound(tmpRslt)
                        ReDim Preserve results(recs)
                        For i=0 To UBound(tmpRslt)
                              results(rec) = tmpRslt(i) & "<a href=""store.asp?category=" & product & """>" & product & "</a> -> "
                        Next
                  End If
            
                  rec = rec + 1
                  rsCategories.MoveNext
            WEnd
      End If
      
      rsCategories.Close()
      Set rsCategories = Nothing
      
      rsCount.Close()
      Set rsCount = Nothing
      
      getCatList = Join(results, "\\""//")
End Function


And here's the data in my DB
CatID      Name      Link      Type
1      Joe      Bob      Child
2      Joe      Jim      Child
3      Joe      Carl      Child
4      Mel      Jim      Child
5      Bob      Joe      Parent
6      Bob      Jerry      Child
7      Bob      Sally      Child
8      Bob      Sandra      Child
9      Jim      Joe      Parent
10      Jim      Mel      Parent
11      Jim      Sandra      Child
12      Carl      Joe      Parent
13      Carl      Andrew      Child
14      Carl      Emily      Child
15      Jerry      Bob      Parent
16      Sally      Bob      Parent
17      Sandra      Bob      Parent
18      Sandra      Audrey      Child
19      Andrew      Jim      Parent
20      Andrew      Carl      Parent
21      Emily      Carl      Parent
22      Audrey      Sandra      Parent
23      Joe      NS_TOP_LVL      Parent
24      Mel      NS_TOP_LVL      Parent
0
Comment
Question by:netsmithcentral
  • 3
  • 2
8 Comments
 
LVL 44

Expert Comment

by:GRayL
ID: 18776191
You never said whether products and categories are linked in a 1-to-many relationship or whether they are many-to-many and need a third table tblProductsCategories to join them correctly.
0
 
LVL 12

Author Comment

by:netsmithcentral
ID: 18776224
They're linked many-to-many, but I don't see why I would need the third table.  Right now, I just use tblCategories with the type 'Product' for products, and include the categories they're in there.  I'm more concerned with the fact that running a query of qType 1 (category) doesn't return an accurate result.
0
 
LVL 2

Expert Comment

by:forrest321
ID: 18777340
Whats the bogus data?  What are you seeing that you dont expect to see?
0
Complete Microsoft Windows PC® & Mac Backup

Backup and recovery solutions to protect all your PCs & Mac– on-premises or in remote locations. Acronis backs up entire PC or Mac with patented reliable disk imaging technology and you will be able to restore workstations to a new, dissimilar hardware in minutes.

 
LVL 12

Author Comment

by:netsmithcentral
ID: 18777432
Here's some of the response data:

getCatList(1, "Joe") = Category Not Found -> Joe\\"//
getCatList(1, "Sandra") = Sandra -> \\"//\\"//\\"//
getCatList(1, "audrey") = audrey -> \\"//\\"//\\"//\\"//
0
 
LVL 12

Accepted Solution

by:
netsmithcentral earned 0 total points
ID: 18818862
Alright, I've solved the problem.  I had about seven errors in that function, all of which I've found and corrected using Response.Write statements to troubleshoot it.  Thanks.
0
 
LVL 44

Expert Comment

by:GRayL
ID: 18818932
Good work!  Sorry we weren't much help.  Good luck with the project.
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

When you are entering numbers in a speadsheet, and don't remember what 6×7 is, you just type “=6*7" instead. It works in every cell! This is not so in Access. To enter the elusive 42 in a text box, you have to find a calculator, and then copy the re…
Introduction When developing Access applications, often we need to know whether an object exists.  This article presents a quick and reliable routine to determine if an object exists without that object being opened. If you wanted to inspect/ite…
In Microsoft Access, learn how to “cascade” or have the displayed data of one combo control depend upon what’s entered in another. Base the dependent combo on a query for its row source: Add a reference to the first combo on the form as criteria i…
With Microsoft Access, learn how to specify relationships between tables and set various options on the relationship. Add the tables: Create the relationship: Decide if you’re going to set referential integrity: Decide if you want cascade upda…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now