我正在维护一些在 Visual Studio 中的表适配器设计器中定义的查询,这些查询用于 Windows 窗体应用程序 (.NET 2.0) 中的一些报告中。当我运行应用程序并执行特定查询时,出现错误:将表达式转换为数据类型 smallmoney 的算术溢出错误。我很惊讶,因为查询应该产生相当小的数量,所以我使用 SQL 分析器捕获了查询,并在 SQL Server Management Studio 中运行了完全相同的查询(显然在同一个数据库上)。这里查询运行没有问题,smallmoney 是“33.00”;不在 214,748.3647 边界附近。
使调试复杂化,此问题仅发生在客户端的 QA 环境中,并且在本地无法重现(并且出于法律原因,无法将数据库复制到开发环境中)。这使得调试周期非常缓慢,因为在客户端环境中构建和部署新版本最多需要 30 分钟,所以我非常感谢一些提示,这些提示将使我通过尽可能少的实验来查明这个问题。在 SQL Studio 中摆弄查询对我没有多大帮助,因为我不能让它产生同样的错误。
这是查询:
SELECT CONVERT(varchar, Events.Occurred, 102) AS Day, Users.Name, COUNT(*) AS Deleted_Invoices, SUM(i.TotalExVat + i.TotalVat) AS Total
FROM Events WITH (nolock) INNER JOIN
Users WITH (nolock) ON Events.UserID = Users.UserID INNER JOIN
Types AS t WITH (nolock) ON t.TypeID = Events.TypeID INNER JOIN
InvoicesEvents AS ie ON ie.EventID = Events.EventID INNER JOIN
Invoices AS i ON i.InvoiceID = ie.InvoiceID
WHERE (Events.Occurred BETWEEN @startDate AND @endDate) AND (t.Name = 'InvoiceDeleted')
GROUP BY CONVERT(varchar, Events.Occurred, 102), Users.Name
ORDER BY Day, Users.Name
TotalExVat 和 TotalVat 是 smallmoney 不为空。数据表中的“Total”字段映射到“System.Decimal”。我可以尝试将 smallmoney 转换为表达式中的钱,但是当它在 SQL 工作室中运行良好时,为什么我必须这样做呢?
我得到的异常是:异常类型:System.Data.SqlClient.SqlException 异常消息:将表达式转换为数据类型 smallmoney 的算术溢出错误。
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.HasMoreRows()
at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
at System.Data.SqlClient.SqlDataReader.Read()
at System.Data.Common.DataAdapter.FillLoadDataRow(SchemaMapping mapping)
at System.Data.Common.DataAdapter.FillFromReader(DataSet dataset, DataTable datatable, String srcTable, DataReaderContainer dataReader, Int32 startRecord, Int32 maxRecords, DataColumn parentChapterColumn, Object parentChapterValue)
at System.Data.Common.DataAdapter.Fill(DataTable[] dataTables, IDataReader dataReader, Int32 startRecord, Int32 maxRecords)
at System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
at System.Data.Common.DbDataAdapter.Fill(DataTable[] dataTables, Int32 startRecord, Int32 maxRecords, IDbCommand command, CommandBehavior behavior)
at System.Data.Common.DbDataAdapter.Fill(DataTable dataTable)
at ... (calling code)
更新
将 SUM(i.TotalExVat + i.TotalVat) 更改为 SUM(i.TotalExVat) + SUM(i.TotalVat) 消除了错误,但我仍然不明白为什么,因为生成的结果中没有 smallmoney 溢出。
更新 2
新问题。现在 smallmoney 铸造问题消失了,但现在我遇到了超时问题。如果在 SSMS 中运行,同一报告中使用的另一个查询将在大约 5-6 秒内运行。如果在表适配器中运行,它会在 10 分钟后超时。其他查询按预期运行,产生与 SSMS 中相同的结果。这支持了我的怀疑,即当我的表适配器尝试查询数据库时,某些事情正在发生。
更新 3
这开始变得奇怪了。smallmoney 问题查询是用于生成报告的一系列查询中的第五个填充查询。在我应用第一次更新中提到的修复后,我在第一个查询中遇到超时。当 smallmoney 在后面的查询中溢出时,该查询运行没有问题。这可能是什么原因?
查询在 smallmoney 查询给出并出错时运行,而在其工作时不运行:
SELECT u.Name AS Username, rea.Text AS DeleteReason, COUNT(*) AS DeletedRegistrations, SUM(r.Shipments) AS DeletedShipments
FROM RecordingsEvents AS re WITH (nolock) INNER JOIN
Events AS e WITH (nolock) ON e.EventID = re.EventID INNER JOIN
Reasons AS rea WITH (nolock) ON rea.ReasonID = e.ReasonID INNER JOIN
Users AS u WITH (nolock) ON u.UserID = e.UserID INNER JOIN
Recordings AS r ON r.RecordingID = re.RecordingID
WHERE (rea.Category = 'DeleteRecording') AND (e.Occurred BETWEEN @startDate AND @endDate)
GROUP BY u.Name, rea.Text
ORDER BY Username, MAX(rea.SortOrder)
如果我限制 smallmoney 查询给出结果 30.0 的日期间隔,则上述查询有效。如果我将日期间隔扩展到 smallmoney 查询也曾经失败的时间段,我会超时。当 smallmoney 查询失败时它运行良好时,如何在 smallmoney 查询之前运行的查询中获得超时?在 SSMS 中运行所有查询按预期工作。顺便说一句,查询同步运行。