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

时间:2016-07-08 16:14:20

标签: .net vb.net ms-access

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

 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是正确的。

2 个答案:

答案 0 :(得分:4)

我无法重现这个问题。也就是说,我赞成使用某种形式的>= 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

结果:

enter image description here

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

请注意OleDBConnectionOleDbCommand之类的内容会分配资源,并且应该在完成后处理。 Using语句为我们做了这个。我还使用了Add而不是AddWithValue,因此可以指定数据类型,让VB / OleDB无法猜测最新情况。此外,不需要临时适配器或DataSet - 您可以使用DataTable直接填充DataReader

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

<强>后记

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

DbCommand个对象是特定于查询的,因为它们可能包含的参数是每次使用Using块时创建,使用和处理它们的另一个原因。

另见:

(这些是博客 - 某些有名望的人的有趣意见 - 而不是用石头雕刻的宙斯之词)

答案 1 :(得分:0)

我认为这是一些时髦的OleDb-ness。在这些情况下,你也可以只是明确:

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