Asp classic 什么';这个ASP递归函数有什么问题?
当我调用这个函数时,只要我不再尝试递归调用该函数,一切都会正常工作。换句话说,如果我取消注释该行:Asp classic 什么';这个ASP递归函数有什么问题?,asp-classic,vbscript,ado,Asp Classic,Vbscript,Ado,当我调用这个函数时,只要我不再尝试递归调用该函数,一切都会正常工作。换句话说,如果我取消注释该行: GetChilds rsData("AcctID"), intLevel + 1 然后函数中断 <% Function GetChilds(ParentID, intLevel) Set rsData= Server.CreateObject("ADODB.Recordset") sSQL = "SELECT AcctID, ParentID FR
GetChilds rsData("AcctID"), intLevel + 1
然后函数中断
<%
Function GetChilds(ParentID, intLevel)
Set rsData= Server.CreateObject("ADODB.Recordset")
sSQL = "SELECT AcctID, ParentID FROM Accounts WHERE ParentID='" & ParentID &"'"
rsData.Open sSQL, conDB, adOpenKeyset, adLockOptimistic
If IsRSEmpty(rsData) Then
Response.Write("Empty")
Else
Do Until rsData.EOF
Response.Write rsData("AcctID") & "<br />"
'GetChilds rsData("AcctID"), intLevel + 1
rsData.MoveNext
Loop
End If
rsData.close: set rsData = nothing
End Function
Call GetChilds(1,0)
%>
我不确定是什么导致了这些问题。我理解这可能是由几个因素造成的
AcctID | ParentID
1 Null
2 1
3 1
4 2
5 2
6 3
7 4
AcctID | ParentID
1 Null
2 1
3 1
4 2
5 2
6 3
7 4
Function GetChilds(ParentID, intLevel)
'Open my Database Connection and Query the current Parent ID
Set rsData= Server.CreateObject("ADODB.Recordset")
sSQL = "SELECT AcctID, ParentID FROM Accounts WHERE ParentID='" & ParentID &"'"
rsData.Open sSQL, conDB, adOpenKeyset, adLockOptimistic
'If the Record Set is not empty continue
If Not IsRSEmpty(rsData) Then
Dim myAccts()
ReDim myAccts(rsData.RecordCount)
Dim i
i = 0
Do Until rsData.EOF
Response.Write "Account ID: " & rsData("AcctID") & " ParentID: " & rsData("ParentID") & "<br />"
'Add the Childs of the current Parent ID to an array.
myAccts(i) = rsData("AcctID")
i = i + 1
rsData.MoveNext
Loop
'Close the SQL connection and get it ready for reopen. (I know not the best way but hey I am just learning this stuff)
rsData.close: set rsData = nothing
'For each Child found in the previous query, now lets get their childs.
For i = 0 To UBound(myAccts)
Call GetChilds(myAccts(i), intLevel + 1)
Next
End If
End Function
Call GetChilds(1,0)
我的想法是,我可以有一个主帐户和子帐户,这些子帐户可以有自己的子帐户。最终将有另一个ParentID为Null的主帐户,它将有自己的孩子。考虑到这一点,我的做法是否正确
谢谢你的快速回复
谢谢大家, 除通常的错误外:
Error Type: (0x80020009) Exception occurred.
错误类型:(0x80020009)异常
发生了
我不确定是什么导致了这些问题。我理解这可能是由几个因素造成的
AcctID | ParentID
1 Null
2 1
3 1
4 2
5 2
6 3
7 4
AcctID | ParentID
1 Null
2 1
3 1
4 2
5 2
6 3
7 4
Function GetChilds(ParentID, intLevel)
'Open my Database Connection and Query the current Parent ID
Set rsData= Server.CreateObject("ADODB.Recordset")
sSQL = "SELECT AcctID, ParentID FROM Accounts WHERE ParentID='" & ParentID &"'"
rsData.Open sSQL, conDB, adOpenKeyset, adLockOptimistic
'If the Record Set is not empty continue
If Not IsRSEmpty(rsData) Then
Dim myAccts()
ReDim myAccts(rsData.RecordCount)
Dim i
i = 0
Do Until rsData.EOF
Response.Write "Account ID: " & rsData("AcctID") & " ParentID: " & rsData("ParentID") & "<br />"
'Add the Childs of the current Parent ID to an array.
myAccts(i) = rsData("AcctID")
i = i + 1
rsData.MoveNext
Loop
'Close the SQL connection and get it ready for reopen. (I know not the best way but hey I am just learning this stuff)
rsData.close: set rsData = nothing
'For each Child found in the previous query, now lets get their childs.
For i = 0 To UBound(myAccts)
Call GetChilds(myAccts(i), intLevel + 1)
Next
End If
End Function
Call GetChilds(1,0)
我的想法是,我可以有一个主帐户和子帐户,这些子帐户可以有自己的子帐户。最终将有另一个ParentID为Null的主帐户,它将有自己的孩子。考虑到这一点,我的做法是否正确
感谢您的快速响应。尝试在函数定义中使用DIM语句将变量声明为本地变量:
Function GetChilds(ParentID, intLevel)
Dim rsData, sSQL
Set ...
编辑:好的,我试着更明确一些
我的理解是,由于rsData不是由DIM声明的,所以它不是局部变量,而是全局变量。因此,如果循环执行WHILE语句,则会到达最内部的rsData记录集的.Eof。您从递归函数调用返回,下一步再次是rsData.MoveNext,它失败了
如果rsData确实是本地的,请纠正我。SQL连接不足 您要处理的层太多(客户机的Response.Write、服务器的ASP和数据库),因此出现问题也就不足为奇了 也许您可以发布一些有关错误的详细信息?它是如何中断的
我的猜测是,经过一定数量的递归之后,您可能会出现堆栈溢出(讽刺的是),因为您没有分配太多的记录集。如果不详细描述它是如何中断的,很难说,但是您没有将intLevel用于任何用途。看起来它失败了,因为您的连接仍在忙着为上一次呼叫的记录集提供服务 一种选择是为每个呼叫使用新的连接。存在的危险是,如果递归次数过多,您将很快耗尽连接 另一种选择是将每个记录集的内容读入一个断开连接的集合:(字典、数组等),以便您可以立即关闭连接。然后迭代断开连接的集合 如果您使用的是SQLServer2005或更高版本,还有一个更好的选择。可以使用CTE(公共表表达式)编写递归sql查询。然后,您可以将所有内容移动到数据库,只需执行一个查询 其他注意事项:
ID字段通常是
int
s,因此不应该将它们封装在sql字符串中的“字符”中
最后,这段代码可能还可以,因为我怀疑用户是否可以直接输入id号。但是,使用的动态sql技术非常危险,通常应该避免使用。改为使用查询参数以防止sql注入
我不太担心什么都不用
intLevel
。从代码上看,这显然是早期版本,以后可以使用intLevel来确定缩进或在设置元素样式时使用的类名。在每次调用中,您打开一个到数据库的新连接,而在打开一个新连接之前,您不会关闭它。这并不是递归问题的实际解决方案,但是,对于您来说,编写一个以分层格式返回所有信息的SQL语句可能比对数据库进行递归调用更好
但仔细想想,这可能是因为您有太多的并发数据库连接。您会不断地打开,但在退出递归循环之前不会开始关闭。如果您需要这样的递归,我会亲自将递归放入存储过程中,并在数据库端处理该处理,以避免打开多个连接。如果您使用的是mssql2005,请查看称为公共表表达式(CTE)的内容,它们使递归变得简单。还有其他方法可以实现与其他RDBMS的递归。基于这些建议,当我找到一个很好的关于如何实现的教程时,我会尝试将查询移动到CTE(公共表表达式)中。现在,作为一个快速而肮脏的修复,我已将代码更改如下:
AcctID | ParentID
1 Null
2 1
3 1
4 2
5 2
6 3
7 4
AcctID | ParentID
1 Null
2 1
3 1
4 2
5 2
6 3
7 4
Function GetChilds(ParentID, intLevel)
'Open my Database Connection and Query the current Parent ID
Set rsData= Server.CreateObject("ADODB.Recordset")
sSQL = "SELECT AcctID, ParentID FROM Accounts WHERE ParentID='" & ParentID &"'"
rsData.Open sSQL, conDB, adOpenKeyset, adLockOptimistic
'If the Record Set is not empty continue
If Not IsRSEmpty(rsData) Then
Dim myAccts()
ReDim myAccts(rsData.RecordCount)
Dim i
i = 0
Do Until rsData.EOF
Response.Write "Account ID: " & rsData("AcctID") & " ParentID: " & rsData("ParentID") & "<br />"
'Add the Childs of the current Parent ID to an array.
myAccts(i) = rsData("AcctID")
i = i + 1
rsData.MoveNext
Loop
'Close the SQL connection and get it ready for reopen. (I know not the best way but hey I am just learning this stuff)
rsData.close: set rsData = nothing
'For each Child found in the previous query, now lets get their childs.
For i = 0 To UBound(myAccts)
Call GetChilds(myAccts(i), intLevel + 1)
Next
End If
End Function
Call GetChilds(1,0)
函数GetChilds(ParentID,intLevel)
'打开我的数据库连接并查询当前父ID
Set rsData=Server.CreateObject(“ADODB.Recordset”)
sSQL=“从ParentID=”&ParentID&“的帐户中选择帐户,ParentID”
打开sSQL、conDB、adOpenKeyset、ADLOCK
'如果记录集不是空的,请继续
如果不是ISSEMPTY(rsData),则
Dim myAccts()
重拨myAccts(rsData.RecordCount)
昏暗的我
i=0
直到rsData.EOF为止
响应。写入“帐户ID:&rsData(“AcctID”)和“家长ID:&rsData(“家长ID”)和”'将当前父ID的子项添加到数组中。 myAccts(i)=r