【问题标题】:How do I use integers in a Visual Basic SQL query?如何在 Visual Basic SQL 查询中使用整数?
【发布时间】:2021-11-02 15:25:51
【问题描述】:

不确定我的问题表述是否正确,但我会详细说明。

我的代码应该将程序中计算的百分比值与 Access 数据库中的相应年级界限进行比较。然后,它会根据课程和等级界限输出字母等级(例如 A*、A、B、C)。但是,我对此的 sql 查询似乎不起作用。

错误消息:“从字符串“SELECT GradeLetter FROM tblGrade”到类型“Double”的转换无效。”

我确信这是一个非常简单的修复方法,但到目前为止我无法在任何地方找到正确的信息,因此我们将不胜感激。

    Private Sub txtDenominator_TextChanged(sender As Object, e As EventArgs) Handles txtDenominator.TextChanged

        Dim Numerator As Integer
        Dim Denominator As Integer
        Dim Percentage As Double

        Numerator = txtNumerator.Text
        Denominator = txtDenominator.Text

        If (Numerator > 0) And (Denominator > 0) And (Numerator <= Denominator) Then
            Percentage = (Numerator / Denominator) * 100
        Else
            Percentage = 0
        End If

        MsgBox(Percentage)

        Dim con As New OleDb.OleDbConnection
        con.ConnectionString = "PROVIDER=Microsoft.ACE.OLEDB.12.0;Data Source = G:/College Database.accdb"
        con.Open()

        sql = "SELECT GradeLetter FROM tblGrades WHERE 
               CourseId = '1' AND (GradeBoundaryLow <= " + Percentage + ")
               AND (GradeBoundaryHigh >= " + Percentage + ")"

        MsgBox(sql)

        da = New OleDb.OleDbDataAdapter(sql, con)
        da.Fill(ds2, "Grades")

        con.Close()

    End Sub

【问题讨论】:

  • 代码比图片更容易处理和理解。
  • 以文本表格的形式提供样本数据和所需的输出也很有帮助。您现在可以删除图像。这只是一种干扰。
  • 如果 tblGrades 有学生成绩结果,为什么该表也会有成绩边界数据?再次提供样本原始数据和所需的输出。
  • 在 Compile 选项卡的 Project Properties 中打开 Option Strict。修复这里指出的错误并编辑您问题中的代码。

标签: sql vb.net ms-access


【解决方案1】:

正如我在 cmets 中所说,您需要做的第一件事是在 Project Properties 中为该项目打开 Option Strict,并在 Tools->Options->Projects and Solutions->VB Defaults 中为所有未来项目打开 Option Strict。

您不能依赖用户在TextBox 中输入您想要的内容。使用.TryParse方法进行验证。

始终使用参数来避免 sql 注入并确保将正确的类型发送到数据库。我假设 CourseId 是数据库中的数字类型。不要用引号括住数字。

需要释放数据库对象。 Using...End Using 块为我们处理这个问题。在这种情况下,连接和命令都包含在同一个Using 块中。注意Using 第一行末尾的逗号。

您可以将连接字符串直接传递给连接的构造函数,将CommandTextConnection 传递给Command 的构造函数。

即使值相同,我们也需要 2 个参数。 OleDb 只考虑参数的位置,而不考虑名称。我使用名称而不是“?”为了可读性。参数在sql字符串中的位置必须与参数添加到参数集合的顺序一致。

.Execute... 之前不要打开连接,并尽快用End Using 关闭它。

由于您只检索单个数据,您可以使用.ExecuteScalar。这会返回一个Object,因此您必须调用.ToString 来分配给GradeLetter

Private Sub txtDenominator_TextChanged(sender As Object, e As EventArgs) Handles txtDenominator.TextChanged
    Dim Numerator As Integer
    Dim Denominator As Integer
    Dim Percentage As Double
    If Not Integer.TryParse(txtNumerator.Text, Numerator) Then
        MessageBox.Show("Please enter a valid number in Numerator")
        Exit Sub
    End If
    If Not Integer.TryParse(txtDenominator.Text, Denominator) Then
        MessageBox.Show("Please enter a valid Denominator")
        Exit Sub
    End If

    If (Numerator > 0) And (Denominator > 0) And (Numerator <= Denominator) Then
        Percentage = (Numerator / Denominator) * 100
    Else
        Percentage = 0
    End If
    Dim GradeLetter As String = ""
    Dim Sql = "SELECT GradeLetter FROM tblGrades 
                WHERE CourseId = 1 
                AND GradeBoundaryLow <= @Percentage
                AND (GradeBoundaryHigh >= @Percentage2;"
    Using con As New OleDb.OleDbConnection("PROVIDER=Microsoft.ACE.OLEDB.12.0;Data Source = G:/College Database.accdb"),
            cmd As New OleDbCommand(Sql, con)
        cmd.Parameters.Add("@Percentage", OleDbType.Double).Value = Percentage
        cmd.Parameters.Add("@Percentage2", OleDbType.Double).Value = Percentage
        con.Open()
        GradeLetter = cmd.ExecuteScalar.ToString
    End Using
    MessageBox.Show($"The grade letter for {Percentage:N2}% is {GradeLetter}")
End Sub

【讨论】:

  • 感谢成为唯一提供一些反 sql 注入黑客建议的人
【解决方案2】:

您收到的错误消息是因为 sql 是一个字符串,而 `percentage 是一个双精度数。

您的快速解决方法是将percentage 转换为带有percentage.tostring() 的字符串。

【讨论】:

  • 其实,快速解决方法是使用 vb "string concat" operator &amp; 而不是 "通常是数字加法,但如果两边都是字符串" operator +
【解决方案3】:

您有 Option Strict Off,并使用+ 将对象“添加”在一起。而Percentage 是一个double,结合这三个事实,你的代码是有效的:

sql = CDbl("SELECT GradeLetter FROM tblGrades WHERE 
               CourseId = '1' AND (GradeBoundaryLow <= ") + Percentage + 
               Cdbl(")
               AND (GradeBoundaryHigh >= ") + Percentage + CDbl(")")

这当然行不通。如果您打开 Option Strict On,编译器会告诉您这一点,但您仍然需要自己修复它。

修复它最简单的方法是使用&amp;而不是+,更正确的方法是使用字符串插值或参数。鉴于该百分比是双倍的(因此没有 sql 注入的危险),我会使用字符串插值,就像这样......

sql = $"SELECT GradeLetter 
        FROM tblGrades 
        WHERE CourseId = '1' AND (GradeBoundaryLow <= {Percentage}
               AND (GradeBoundaryHigh >= {Percentage}"

除非您需要性能,否则我建议您使用 Decimal 作为您的百分比。

【讨论】:

  • 是的,虽然我更喜欢一个教导如何避免 sql 注入黑客攻击的解决方案,即使它不能在这里发生
  • @CaiusJard:我想过这个问题,但我想解释发生了什么,而不是展示在这种特殊情况下解决问题的方法。
  • 同意,但值得指出的是,使用参数也可以解决问题,因为它本质上是由未参数化引起的:D
【解决方案4】:

如果字段是数字类型,不要用撇号包围参数。可能需要行继续符,每行部分用引号括起来。尝试 BETWEEN AND 语法。考虑:

sql = "SELECT GradeLetter FROM tblGrades " & _
      "WHERE CourseId = 1 AND " & Percentage & " BETWEEN GradeBoundaryLow AND GradeBoundaryHigh"

关于字符串连接字符,查看https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/operators-and-expressions/concatenation-operators

【讨论】:

  • 是的,虽然我更喜欢一个教导如何避免 sql 注入黑客攻击的解决方案,即使它不能在这里发生
猜你喜欢
  • 1970-01-01
  • 2013-02-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多