存储过程不会返回与构造的SQL字符串相同的结果

时间:2016-06-24 14:47:58

标签: c# sql-server

我有一个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字符串返回我期望的内容时,是什么导致存储过程不返回行?我确定它很小,会导致其中一个“噢!”一旦它被指出,就会出现。

1 个答案:

答案 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 + "'";