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] 值超出了 heightMin
到 heightMax
的范围。
如果不使用.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"
返回相同的结果。
请注意,OleDBConnection
和 OleDbCommand
之类的东西会分配资源,并且应该在您使用完它们后进行处置。 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 的结果,但它返回小于和等于子查询的结果
标准 SQL 查询在 BigQuery 中返回正确结果,但在 Data Studio 中不返回