【问题标题】:How to use ASP variables in SQL statement如何在 SQL 语句中使用 ASP 变量
【发布时间】:2013-12-18 13:50:11
【问题描述】:
<%
postit = request.querystring("thispost")
response.write(postit)
%> 

postit 是变量。 response.write 有效,这都在下面的 SQL 语句之上。

这是 SQL,但是当我添加 postit 变量时,我收到以下错误消息:

delCmd.CommandText="DELETE * FROM post WHERE (pos_ID = postit )"
Microsoft Access Database Engine error '80040e10'
No value given for one or more required parameters. 
/student/s0190204/wip/deleterecord.asp, line 32

【问题讨论】:

    标签: sql asp-classic


    【解决方案1】:

    在 SQL 中添加参数:

    delCmd.CommandText="DELETE * FROM post WHERE (pos_ID = ?)"
    delCmd.Parameters.Append delCmd.CreateParameter("posid", adInteger, adParamInput)   ' input parameter
    delCmd.Parameters("posid").Value = postit
    

    【讨论】:

    • 参数 ?_1 没有默认值。
    • @Jayyf9 它应该可以工作,但您可能需要在单独的行上设置值。请参阅我的更新答案。
    • 问题是变量名——应该是postit而不是posid
    • @Jayyf9:在 ASP 页面的开头打开 Option Explicit 总是一个好主意。
    【解决方案2】:

    对你未来有帮助的几件事

    1. 使用Option Explicit 避免隐藏问题,这些问题稍后会再次困扰您
    2. 使用ADODB.Command 对象,它非常通用,可以执行一系列数据库调用,从简单的动态 SQL 语句到存储过程,没有 SQL 注入的风险。

    在您的代码中使用ADODB.Command 对象时,有一些技巧可以加快处理速度,这将在下面的示例中进行演示(假设您已经在全局配置调用gs_connstr 中存储了一个连接字符串);

    <%
    Option Explicit
    
    Dim postit
    postit = Request.QueryString("thispost")
    'Always do some basic validation of your Request variables
    If Len(postit) > 0 And IsNumeric(postit) Then CLng(postit) Else postit = 0
    
    Dim o_cmd, o_rs, a_rs, i_row, i_rows, l_affected
    Dim SQL
    
    'SQL statement to be executed. For CommandType adCmdText this can be any dynamic
    'statement, but adCmdText also gives you an added bonus - Parameterised Queries
    'instead of concatenating values into your SQL you can specify placeholders (?)
    'that you will define values for that will get passed to the provider in the order
    'they are defined in the SQL statement.
    SQL = "DELETE * FROM post WHERE (pos_ID = ?)"
    
    Set o_cmd = Server.CreateObject("ADODB.Command")
    With o_cmd
      'ActiveConnection will accept a Connection String so there is no need
      'to instantiate a separate ADODB.Connection object the ADODB.Command object
      'will handle this and also open the connection ready.
      .ActiveConnection = gs_connstr
      .CommandType = adCmdText
      .CommandText = SQL
      'When using Parameters the most important thing to remember is the order you
      'appended your parameters to the Parameters collection as this will determine
      'the order in which they are applied to your SQL query at execution. Because
      'of this the name you give to your parameters is not important in terms of
      'execution but I find specifying a meaningful name is best (especially when
      'revisiting some code a few years down the line).
      Call .Parameters.Append(.CreateParameter("@pos_ID", adInteger, adParamInput, 4))
      'Parameter values can be passed in via the Execute() method using an Array
      'without having to define the parameter values explicitly. You can also specify
      'the records affected value to return number of rows affected by a DELETE,
      'INSERT or UPDATE statement.
      .Execute(l_affected, Array(postit))
    End With
    'Always tidy up after yourself, by releasing your object from memory, this will
    'also tidy up your connection as it was created by the ADODB.Command object.
    Set o_cmd = Nothing
    %>
    

    【讨论】:

      【解决方案3】:

      试试这个代码:

      <% Dim postit, stringSQL, objectCon
         postit = request.querystring("thispost")
      
         Set objectCon = Server.CreateObject("ADODB.Connection")
         objectCon.ConnectionString  "Driver={SQL SERVER};Server=server_name;UID=user_name;PWD=password;Database=database_name" 'SET CONNECTION STRING OF YOUR DATABASE
         stringSQL = "DELETE FROM post WHERE pos_id='" & postit & "'"
      
         objectCon.Open
         objectCon.Execute(stringSQL)
         objectCon.Close() %>
      

      【讨论】:

        【解决方案4】:

        您没有将 postit 的值传递给 Access;相反,您是在告诉 Access 查找并使用名为 postit 的变量。当然,所述变量在 Access 中不存在——它只存在于您的代码中。修复只是几个引号和一对&符号。

        delCmd.CommandText="DELETE * FROM post WHERE (pos_ID = " & postit & " )"
        

        (当然,您应该在将postit 发送到数据库之前对其进行验证。假设它是一个数值,一个简单的CDbl() 就可以解决问题。)

        【讨论】:

        • 个人不太喜欢在 SQL 查询中使用串联,参数化查询更安全且易于阅读。
        【解决方案5】:

        在这里,我尝试使用汽车的id 获取汽车的car_color。 现在我可以在我的代码中使用car_color 记录集。 我还建议在传入值时使用CLng,它会阻止sql注入。

        如果carID 不是数字,您将收到以下错误:

        “来自服务器的500响应。记得打开和关闭sql连接。”

        代码如下:

        sql = "Select * from Cars Where ID = " & clng(carID)
            rs.open
            if not rs.eof then
              carID = rs("car_ID")
              carColor = rs("car_color")
            end if
            rs.close
        

        【讨论】:

          【解决方案6】:

          更容易删除,这种方式在不需要检查记录集时很有用:

          cn.open "yourconnectionstring"
          cn.execute "DELETE * FROM post WHERE pos_ID = " & request.querystring("thispost")
          cn.close
          

          【讨论】:

          • 这种方法的问题是我们不知道thispost(在你的情况下)来自哪里,并打开应用程序到SQL injection attacks
          • 没有提到参数的验证。我尝试使用相同的请求来解释值的来源。
          • 参数化和验证在这样的 DELETE 语句的情况下尤其重要。想象一下有人提交了foo OR 1 = 1 的这篇文章。这将删除表中的每条记录。
          猜你喜欢
          • 1970-01-01
          • 2011-01-12
          • 2022-12-21
          • 2010-10-28
          相关资源
          最近更新 更多