SQL BETWEEN 查询返回不正确的结果

Posted

技术标签:

【中文标题】SQL BETWEEN 查询返回不正确的结果【英文标题】:SQL BETWEEN Query returning incorrect results 【发布时间】:2016-07-08 16:14:20 【问题描述】:

我正在编写一个 vb.net 应用程序,它正在搜索 Access 2010 数据库并且遇到了一个我似乎无法解决的问题。下面这段代码就是问题所在。

 Using SQLcon 'public property containing OleDbConnection
    Dim ds As New DataSet
    Dim da As New OleDbDataAdapter
    Dim cmd As New OleDbCommand

    cmd.Connection = SQLcon
    cmd.CommandType = CommandType.Text

    Dim heightMin As Double = OverallHeight - 0.25
    Dim heightMax As Double = OverallHeight + 0.125

    cmd.CommandText = "SELECT * FROM [CAGE - BARREL] WHERE [Type]=@p1 AND [Valve Size]=@p2 AND [Cage Height] BETWEEN @p3 AND @p4"
    cmd.Parameters.AddWithValue("@p1", CageType) '[Type]
    cmd.Parameters.AddWithValue("@p2", ValveSize) '[Valve Size]
    cmd.Parameters.AddWithValue("@p3", heightMin) '[Cage Height]
    cmd.Parameters.AddWithValue("@p4", heightMax) '[Cage Height]

    da = New OleDbDataAdapter(cmd)
    SQLcon.Open()
    da.Fill(ds, "[CAGE - BARREL]")
    SQLcon.Close()
End Using

当我使用一组特定的值直接在 Access 中运行 SQL 语句时,我得到了预期的 3 个结果。当我通过我的程序运行它时,我得到 6,其中 3 个值超出了 BETWEEN 语句的范围。我已经仔细检查了 Access 中字段的数据类型和 vb.net 中的变量。我知道我错过了一些东西。有没有人知道我哪里出错了?

更新:

使用的值如下。

@p1="INLET"
@p2="10.50" 'this is a text field
@p3=heightMin=6 'this is a number/double
@p4=heightMax=6.375 'this is a number/double

.net 程序返回的值包括超出上述范围的 5,5 和 3.688 以及正确的 6、6 和 6.188。

【问题讨论】:

您能否edit 您的问题提供说明问题的示例值?例如,“当我将 OverallHeight 指定为 ___ 时,我得到的行包含的 [Cage Height] 值超出了 heightMinheightMax 的范围。 如果不使用.AddWithValue,例如cmd.Parameters.Add(New OleDbParameter With .ParameterName = "@p3", .OleDbType = OleDbType.Double, .Value = heightMin),它是否有效? (对于其他参数也是如此。) [Cage - Barrel] 是一张桌子 【参考方案1】:

我无法重现该问题(或者)。也就是说,我倾向于使用某种形式的>= AND <= 来代替BETWEEN

测试数据:

Id  CageType    ValveSize   Height
1     A            XS       0.25
2     A            S        0.51
3     A            S2       0.55
4     A            M        0.95
5     A            L        1.26
6     B            S        0.58

代码:

Dim sql1 = "SELECT * FROM Cage WHERE CageType=@p1 AND ValveSize=@p2 AND Height BETWEEN @p3 AND @p4"
Dim sql2 = "SELECT * FROM Cage WHERE ValveSize=@p2 AND Height BETWEEN @p3 AND @p4"

Dim t As String = "A"
Dim v As String = "S"
Dim minH As Double = 0.45
Dim maxH As Double = 0.65

Dim dt As New DataTable
Using dbcon As New OleDbConnection(ACEConnStr)
    Using cmd As New OleDbCommand(sql2, dbcon)
        dbcon.Open()

        ' only used with 'sql1':
        'cmd.Parameters.Add("@p1", OleDbType.VarChar).Value = t
        cmd.Parameters.Add("@p2", OleDbType.VarChar).Value = v
        cmd.Parameters.Add("@p3", OleDbType.Double).Value = minH
        cmd.Parameters.Add("@p4", OleDbType.Double).Value = maxH

        dt.Load(cmd.ExecuteReader)
        dgv1.DataSource = dt
    End Using
End Using

结果:

我认为您的数据或数据类型有些奇怪。列出了 2 个 SQL 语句,仅用于测试并减少所需的测试数据量。 "SELECT * FROM Cage WHERE ValveSize=@p2 AND Height > @p3 AND Height <= @p4" 返回相同的结果。

请注意,OleDBConnectionOleDbCommand 之类的东西会分配资源,并且应该在您使用完它们后进行处置。 Using 语句为我们做到了这一点。我还使用了Add 而不是AddWithValue,以便可以指定数据类型,让VB/OleDB 没有猜测发生了什么的余地。此外,不需要临时适配器或DataSet - 您可以直接用DataReader 填充DataTable

还要注意OleDb 不使用命名参数,它们只是位置占位符。使用OleDb,您必须 Add 它们按照它们在SQL 中出现的确切顺序。你的可以,但这解释了为什么上面的代码可以注释掉 @p1 参数并且仍然有效。


后记

正如在某些时候可能会被删除的 cmets 中所述,真正的问题是 OleDbCommand 被重新使用。因此,它可能具有上次遗留下来的参数或值。这意味着发布的代码不是导致问题的真实代码。

DbCommand 对象是特定于查询的对象,因为它们可能包含参数,这是另一个像Using 块一样创建、使用和处置它们的原因。


另见:

What do BETWEEN and the devil have in common? Can we stop using AddWithValue() already?

(这些是博客 - 某些知名人士的有趣意见 - 不是刻在石头上的宙斯的话)

【讨论】:

【参考方案2】:

我认为这是一些时髦的 OleDb 特性。在这些情况下,您不妨直言不讳:

SELECT * 
FROM [CAGE - BARREL] 
WHERE [Type] = @p1 
    AND [Valve Size] = @p2 
    AND [Cage Height] >= @p3 
    AND [Cage Height] <= @p4

【讨论】:

使用该方法时,我的 .net 程序返回了 0 条记录。虽然它在 Access 中完美运行。这真是令人沮丧。 @Mike 很奇怪。你确定这不是数据类型问题吗?你的参数的数据类型是什么,cage height列的数据类型是什么? Access 是 Number 类型,size double 并且我的代码中的变量是 double。

以上是关于SQL BETWEEN 查询返回不正确的结果的主要内容,如果未能解决你的问题,请参考以下文章

MYSQL 查询不返回 BETWEEN 的结果,但它返回小于和等于子查询的结果

SqlServer2005 第三讲 between

标准 SQL 查询在 BigQuery 中返回正确结果,但在 Data Studio 中不返回

SQL BETWEEN Time 不显示结果

SQL Server 查询使用 BETWEEN 过滤器带来不匹配的数据

使用 between 语句查询包含数字的 SQL 列 varchar6