2012-06-16 462 views
2

我最近在ASP中继承了一个网站,这是我不熟悉的。昨日,页面一开始抛出一个错误:Microsoft VBScript运行时错误'800a0009'

Microsoft VBScript runtime error '800a0009' 

Subscript out of range: 'i' 

default.asp, line 19 

下面是从第13-27行的代码:

<% 
set rs = Server.CreateObject("ADODB.Recordset") 
rs.open "SELECT * FROM VENDORS_LIST_TBL WHERE inStr('"& dVendorStr &"','|'&ID&'|')", Cn 

DIM dTitle(100), dDescription(100), dLink(100) 
i = 0 : Do while NOT rs.EOF : i = i + 1 
dTitle(i) = rs.fields.item("dTitle").value 
dDescription(i) = rs.fields.item("dDescription").value 
dLink(i) = rs.fields.item("dLink").value : if dLink(i) <> "" then dTitle(i) = "<a href=""" & dLink(i) & """>" & dTitle(i) & "</a>" 
if NOT rs.EOF then rs.movenext 
Loop 
x = i 

rs.Close : Set rs = Nothing 
%> 

在这里发生了什么任何想法,我该如何解决?

谢谢!

+1

您可能会考虑ADO Recordset的GetRows方法,该方法返回两维数组。 – AnthonyWJones

+0

鉴于其他两个答案,有必要向您提供“这是应该如何完成”的答案。 – AnthonyWJones

回答

2

您已将dTitle,dDescription和dLink声明为大小为数组的数组。当您在记录集中漫步时,您正在为这些数组指定元素。这样看来,你有超过100个记录在您的记录,所以逻辑是试图做这样的事情:

dTitle(101) = rs.fields.item("dTitle").value 

这将抛出一个错误,因为你的阵列是不是大到足以容纳所有数据。

+0

谢谢你修好了!我增加了限制到500. –

+3

重新:*我增加了限制到500. *这是一个坏主意。您不需要将限制设置为静态数字。像这样:http://stackoverflow.com/a/11072016/48082 – Cheeso

2

您选择的“解决方案”不太好。如果两年之内会有超过500个呢?你会忘记这一切,并再次浪费时间。

而是固定大小的数组,你可以只使用动态数组:

DIM dTitle(), dDescription(), dLink() 
ReDim dTitle(0) 
ReDim dDescription(0) 
ReDim dLink(0) 
i = 0 
Do while NOT rs.EOF 
    i = i + 1 
    ReDim Preserve dTitle(i) 
    ReDim Preserve dDescription(i) 
    ReDim Preserve dLink(i)  
    dTitle(i) = rs.fields.item("dTitle").value 
    dDescription(i) = rs.fields.item("dDescription").value 
    dLink(i) = rs.fields.item("dLink").value 
    If (Not(IsNull(dLink(i)))) And (dLink(i) <> "") Then 
     dTitle(i) = "<a href=""" & dLink(i) & """>" & dTitle(i) & "</a>" 
    End If 
    rs.movenext 
Loop 

这将每个数组中的一个(空)项目启动 - 由于某种原因代码似乎需要这个 - 然后在每次迭代将增加一个项目,保留其他项目。

请注意,我也修复了一个可能会造成麻烦的小问题 - 在“dLink”字段中为NULL值的情况下,由于在VBScript中NULL不是空字符串,

+0

不要使用这种方法。while循环的每一次访问(即对于每个记录),每个数组需要分配一个新的内存块,将其所有当前元素复制到新块并释放先前的数组内存。对于一些记录来说这可能是正确的,但会随着记录数量的增加呈指数级下降。 – AnthonyWJones

+0

@AnthonyWJones你认为〜100个记录大数?随着现代的CPU和内存,我不认为这是一个问题。然而,每次分配50个项目仍然非常简单 - 仍然比固定大小的阵列可能失败要好。 –

+0

Stackoverflow中的答案不仅仅是为了提问者的唯一好处。可能只有一百条记录,这可能不会太糟糕,但总的来说这是不好的做法。当然,问题没有说明的是,有多少并发的ASP请求可能同时运行此代码。 20个并发活动请求将有效地将数组的300个重新分配转换为6000.这也表示64位内存空间的快速碎片化,这可能不是问题,但我已经看到它过去对32位服务器不利。 – AnthonyWJones

1

这个如何GetRows可以用来实现相同的目标。

<% 

Function VendorSearch(sVendor) 

    Dim cn: Set cn = SomeLibraryFunctionThatOpensAConnection() 
    Dim cmd: Set cmd = Server.CreateObject("ADODB.Command") 
    cmd.CommandType = adCmdText 
    cmd.CommandText = "SELECT dTitle, dDescription, dLink FROM VENDORS_LIST_TBL WHERE inStr(?,'|'&ID&'|')" 
    cmd.Parameters.Append cmd.CreateParameter("Vendor", adVarChar, adParamInput, Len(sVendor), sVendor) 
    Set cmd.ActiveConnection = cn 
    Dim rs : Set rs = cmd.Execute() 

    VendorSearch = rs.GetRows() 

    rs.Close() 
    cn.Close() 
End Function 

Dim arrVendor : arrVendor = VendorSearch(dVendorStr) 

Const cTitle = 0, cDesc = 1, cLink = 2 

Dim i 
For i = 0 To UBound(arrVendor, 2) 
    If IsNull(arrVendor(cLink, i) Or arrVendor(cLink, i) = "" Then 
     arrVendor(cTitle, i) = "<a href=""" & arrVendor(cLink, i) & """>" & arr(cTitle, i) & "</a>" 
    End If 
Next 

%> 

注:

  • 的SELECT语句包含只在结果所需的那些领域,使用*应避免
  • 一个参数化的命令是用来避免SQL contactenation SQL注入威胁。
  • 将字段索引用于生成的2维数组的常量。
  • 虽然这段代码复制了原始标题值,但这里仅作为示例。实际上,HTML的构建应该尽可能晚,并且在发送到响应之前应该通过Server.HTMLEncode传递所有诸如标题和描述的字符串的输出。
相关问题