与直接在 Access 中查询相比,使用 OleDb 查询时的结果不同
Posted
技术标签:
【中文标题】与直接在 Access 中查询相比,使用 OleDb 查询时的结果不同【英文标题】:Different results when querying with OleDb compared to directly in Access 【发布时间】:2013-08-20 14:13:40 【问题描述】:我们目前在几个内部产品中使用 ADO.Net,其中一个产品必须使用 OleDB 查询 Microsoft Access 数据库。我们现在遇到的问题是,当OleDbDataAdapter.Fill
执行和直接在 Microsoft Access 的 SQL 视图中执行时,其中一个查询不会产生相同的结果。
查询如下所示:
SELECT DISTINCT t1.*
FROM tableOne AS t1
INNER JOIN tableTwo AS t2 ON t2.tableOne_no = t1.tableOne_no
WHERE t1.status = 'A'
AND t2.tableThree_no = @p_tableThree_no
AND t2.status = 1
AND (t2.startDate IS NULL OR (YEAR(t2.startDate) <= @p_year AND MONTH(t2.startDate) <= @p_month))
AND (t2.endDate IS NULL OR (YEAR(t2.endDate) >= @p_year AND MONTH(t2.endDate) >= @p_month))
我们使用以下代码查询数据库,使用 Microsoft ACE OLEDB 12 和 ADO.Net:
Dim oDataSet As New DataSet()
Using oSqlConnection As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=\\NetworkDrive\database.mdb;User Id=admin;Password=password;")
Using oSqlCommand As New OleDbCommand(p_sQuery, oSqlConnection)
oSqlCommand.Parameters.AddWithValue("@p_tableThree_no", 1111)
oSqlCommand.Parameters.AddWithValue("@p_year", 2013)
oSqlCommand.Parameters.AddWithValue("@p_month", 7)
oSqlCommand.CommandType = CommandType.Text
Using oDataAdapter As New OleDbDataAdapter()
oDataAdapter.SelectCommand = oSqlCommand
oSqlConnection.Open()
oDataAdapter.Fill(oDataSet)
End Using
End Using
End Using
不知何故,从 OleDB 执行查询所提供的结果数量与在 Microsoft Access 中执行相同的查询不同(Access 具有正确数量的结果)。当使用不同的@p_tableThree_no
值执行相同的查询时,一切似乎都很好。是否有可能来自某些文本字段的特定值会导致 OleDB 在特定情况下忽略行?没有错误信息,代码运行成功,只有错误的结果。
在 Google 和 *** 上搜索此问题几乎没有帮助,因为我发现的唯一解决方案是针对 LIKE
语句(使用 % 而不是 *)和参数名称冲突的问题,这与我的无关情况。
我错过了什么吗?查询对于 OleDB 来说是否太复杂?我应该用括号括起来吗?我不知道我做错了什么。
编辑和解决方案
原来这个查询一开始就错了,而且没有人(包括我自己)第一眼就发现了它。当我注意到 MONTH(t2.startDate) <= @p_month
如果日期是例如 2012-11 而不是 2013-07 时,我正在重写来自 stratch 的查询。我仍然不知道为什么直接在 Access 中执行并在弹出窗口中提供参数时查询结果“错误正确”,但这是我不愿意解决的另一个谜团。我接受了@HansUp 的回答,因为他确实向我提供了一个双方都相同的查询,而且他是让我对 SQL 本身产生怀疑的人。
【问题讨论】:
tableThree_no的数据类型是什么? tableThree_no 字段是 Access 中的 Number (Long Integer) 类型。该参数是 .Net 中的整数类型。针对特定情况传递的值完全符合整数的“限制”,并且来自之前在 .Net 应用程序中检索到的另一个数字(长整数)字段。 【参考方案1】:在 SQL 语句中定义参数,然后像以前一样从代码中提供值。
不要担心Parameters.AddWithValue
中的参数名称。 OleDb 忽略参数名称......你可以做.AddWithValue("Hello World!", 1111)
,它不会改变任何东西。但是,您必须按照 Access 期望的顺序提供参数,我希望添加 PARAMETERS
子句可以避免混淆。
PARAMETERS
p_tableThree_no Long,
p_year Long,
p_month Long;
SELECT DISTINCT t1.*
FROM
tableOne AS t1
INNER JOIN
tableTwo AS t2
ON t2.tableOne_no = t1.tableOne_no
WHERE
t1.status = 'A'
AND t2.tableThree_no = p_tableThree_no
AND t2.status = 1
AND (t2.startDate IS NULL
OR (YEAR(t2.startDate) <= p_year AND MONTH(t2.startDate) <= p_month))
AND (t2.endDate IS NULL
OR (YEAR(t2.endDate) >= p_year AND MONTH(t2.endDate) >= p_month))
【讨论】:
令人惊讶的是,在 Access 中直接执行时,添加PARAMETERS
子句会导致查询产生错误的结果(与 OleDB 相同)。
该查询使用 OleDb 给出的结果与直接在 Access 中运行时的结果相同。现在你得到了相同的结果,你的问题已经转移到“但这不是我想要的结果”。这和你问的问题不同。我鼓励您将该问题作为一个新问题提出。
感谢您的帮助,但是在没有参数定义的情况下直接在Access中执行查询时,Access会在弹出窗口中询问参数值(无论是命名还是?
)和结果是正确的。引入PARAMETERS
子句让他们错了。我的问题更多是关于“如何使 OleDB 产生与 Access 相同的结果,因为 Access 具有正确的结果”。
您现在有一个 Access 查询,它在 Access 和 OleDb 中产生相同的结果。现在修改 Access 查询,保留 PARAMETERS
子句,直到它在 Access 中返回您想要的结果。当您到达该点时,相同的查询将返回与 OleDb 相同的结果。
除非证明 OleDB 自动在其执行的查询中包含 PARAMETERS
子句,否则我无法确定添加该子句并重构查询以使其直接在 Access 中工作会使其在 OleDB 中工作. OleDB可能在其查询中添加PARAMETERS
子句这一事实可能是开始的问题/解决方案。【参考方案2】:
ACE.OLEDB 忽略参数名称,因此 OleDb 查询可能会变得混乱,因为 @p_year
和 @p_month
参数在 SQL 命令中重复但它们仅在 OleDbCommand.Parameters
集合中指定一次。我倾向于尝试使用?
作为参数占位符并重复最后两个参数(即,使用五个AddWithValue
语句而不是三个)。
【讨论】:
我尝试了您的建议,但似乎无法解决问题。我将查询更改为仅使用?
参数,并将AddWithValue
复制为p_year
和p_month
。我的查询中有 5 个?
,我添加了 5 个参数,例如,oSqlCommand.Parameters.AddWithValue("", 2013)
。以上是关于与直接在 Access 中查询相比,使用 OleDb 查询时的结果不同的主要内容,如果未能解决你的问题,请参考以下文章