我有一个C#控制台应用程序,可以从SQL Server数据库生成报告。我的所有报告都基于存储过程,我的应用程序代码以相同的方式调用存储过程。
我遇到过一个问题,即一个存储过程在我的应用程序中没有按照预期的方式运行,尽管从SQL Server Management Studio运行时存储过程按预期运行。
我最终试图解决这个问题。我已经尽可能多地解剖它,只需要额外的一双眼睛来检查这段代码,但我仍然无法让它工作。
// code in my app
public DataTable DeviceAuthorizationAffectedDeviceGroup(string affectedDeviceGroupNameArray, DateTime startDate, int deviceId) {
dt = new DataTable();
DataTable dt2 = new DataTable();
string sql = "SELECT StartTime EventTime, EventText, UserName AS Username, AffectedDeviceGroupName";
sql += " FROM eventlog";
sql += " WHERE AffectedDeviceGroupName IN (SELECT LTRIM(RTRIM(Item)) FROM dbo.SplitString('" + affectedDeviceGroupNameArray + "', ','))";
sql += " AND StartTime >= '" + startDate + "'";
sql += " AND (DeviceID = " + deviceId + ")";
sql += " ORDER BY StartTime";
using (var cn = new SqlConnection(this.ConnectionString)) {
using (var cmd = new SqlCommand(sql, cn)) {
using (var da = new SqlDataAdapter(cmd)) {
cmd.CommandType = CommandType.Text;
Debug.WriteLine(MyDamnClass.CommandAsSql(cmd));
da.Fill(dt); //SQL string, data table contains 6 rows
}
}
using (var cmd = new SqlCommand("usp_REPORTS_SubReport_GetDeviceAuthorizationAffectedDeviceGroup_TEST", cn)) {
using (var da = new SqlDataAdapter(cmd)) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@AffectedDeviceGroupNameArray", SqlDbType.VarChar).Value = affectedDeviceGroupNameArray;
cmd.Parameters.Add("@StartTime", SqlDbType.DateTime).Value = startDate;
cmd.Parameters.Add("@DeviceID", SqlDbType.Int).Value = deviceId;
Debug.WriteLine(MyDamnClass.CommandAsSql(cmd));
da.Fill(dt2); //stored proc, data table contains 0 rows
}
}
}
return dt;
} // breakpoint here to examine the contents of each data table
服务器上的存储过程:
CREATE PROCEDURE [dbo].[usp_REPORTS_SubReport_GetDeviceAuthorizationAffectedDeviceGroup_TEST]
(@AffectedDeviceGroupNameArray varchar(MAX),
@StartTime datetime, @DeviceID int)
AS
SELECT
StartTime EventTime,
EventText,
UserName AS Username,
AffectedDeviceGroupName
FROM
eventlog
WHERE
AffectedDeviceGroupName IN (SELECT LTRIM(RTRIM(Item))
FROM dbo.SplitString(@AffectedDeviceGroupNameArray, ','))
AND StartTime >= @StartTime
AND (DeviceID = @DeviceID)
ORDER BY
StartTime
从我的应用程序执行的SQL代码(使用来自this question的@ Flapper代码)
use MyDatabase;
SELECT
StartTime EventTime, EventText, UserName AS Username,
AffectedDeviceGroupName
FROM
eventlog
WHERE
AffectedDeviceGroupName IN (SELECT LTRIM(RTRIM(Item))
FROM dbo.SplitString('(Unassigned)', ','))
AND StartTime >= '10/12/2015 2:46:51 PM'
AND (DeviceID = 281)
ORDER BY
StartTime
use MyDatabase;
declare @return_value int;
exec [usp_REPORTS_SubReport_GetDeviceAuthorizationAffectedDeviceGroup_TEST]
@AffectedDeviceGroupNameArray = '(Unassigned)'
, @StartTime = '10/12/2015 2:46:51 PM'
, @DeviceID = 281
;
select 'Return Value' = convert(varchar, @return_value);
我没看到什么?当相同构造的SQL字符串返回我期望的内容时,是什么导致存储过程不返回行?我确定它很小,会导致其中一个“噢!”一旦它被指出,就会出现。
答案 0 :(得分:1)
通过串联字符串构建的select语句与存储过程的执行之间的一个区别是您要比较的参数的数据类型。根据表字段的数据类型,这可能会改变方法之间的结果。特别是,如果StartTime
表中的eventlog
字段是varchar而不是datetime,则会得到不同的结果。
在您的选择查询中,您将StartTime字段与字符串文字进行比较:
StartTime >= '" + startDate + "'";
如果StartTime
是varchar类型,这将导致字符串比较而不是日期比较,这不是您想要的。它会按字母顺序对日期进行排序,例如' 10/12/2015 2:46:51 PM'将大于< 01/12/2016 2:46:51 PM'因为它以1开头,而另一个以0开头。
但是,当您将StartTime
字段与存储过程中的参数进行比较时,它会将数据与日期时间进行比较。由于数据类型优先,它将尝试将表字段隐式转换为日期时间数据类型,然后将两者作为日期进行比较。
如果您显式转换为StartTime字段或字符串参数的datetime,则应使用这两种方法获得相同的结果:
convert(datetime, StartTime) >= '" + startDate + "'";