TSQL正常工作但不通过sp_executesql

时间:2015-03-24 16:12:48

标签: c# sql-server sql-server-2008 datetime

我有一些看起来像这样的C#代码:

string strSql = "SELECT DISTINCT A." + strProcessingDateColumn
        + " FROM GA_Item A "
        + " WHERE A.TOWControlID = @TOWControlID"
        + " AND A.ItemTypeExt = 'PDF' "
        + " AND A." + strSourceColumn + " = 'Teller Report' "
        + " AND A." + strReportNumberColumn + " = @ReportNum "
        + " AND A." + strIBTColumn + " <> '9999' "
        + " AND ISNULL(A." + strMergedColumn + ", 'N') = 'N'"
        + " AND CAST(LTRIM(RTRIM(A." + strProcessingDateColumn + ")) AS DATETIME) < @ProcessingDate";
      using (SqlCommand command = new SqlCommand(strSql, conn))
      {
        command.Parameters.AddWithValue("@TOWControlID", iTOWControlID);
        command.Parameters.AddWithValue("@ReportNum", iReportNumber.ToString());
        command.Parameters.AddWithValue("@ProcessingDate", dtCurrentDate);
        try
        {
          using (SqlDataReader datereader = command.ExecuteReader())
          {
            while (datereader.Read())
            {
              //...
            }
          }
        }
      }

这会生成一个sp_executesql语句(我从SQL分析器中提取),如下所示:

exec sp_executesql N'SELECT DISTINCT A.UserField1 FROM GA_Item A
WHERE A.TOWControlID = @TOWControlID
    AND A.ItemTypeExt = ''PDF''
    AND A.UserField4 = ''Teller Report''
    AND A.UserField3 = @ReportNum
    AND A.UserField2 <> ''9999''
    AND ISNULL(A.UserField5, ''N'') = ''N''
    AND CAST(LTRIM(RTRIM(A.UserField1)) AS DATETIME) < @ProcessingDate'
,N'@TOWControlID int,@ReportNum nvarchar(1),@ProcessingDate datetime'
,@TOWControlID=9999
,@ReportNum=N'6'
,@ProcessingDate='2015-03-24 00:00:00'

导致2个错误:The conversion of a nvarchar data type to a datetime data type resulted in an out-of-range value.Conversion failed when converting date and/or time from character string.

这让我相信某些东西正在导致我正在选择的表中出现溢出。但是,如果我从sp_executesql语句中提取查询,那么它看起来像这样:

declare @TOWControlID int = 9999,
        @ReportNum nvarchar = '6',
        @ProcessingDate datetime = '2015-03-24'
SELECT DISTINCT A.UserField1 FROM GA_Item A
WHERE A.TOWControlID = @TOWControlID
      AND A.ItemTypeExt = 'PDF'
      AND A.UserField4 = 'Teller Report'
      AND A.UserField3 = @ReportNum
      AND A.UserField2 <> '9999'
      AND ISNULL(A.UserField5, 'N') = 'N'
      AND CAST(LTRIM(RTRIM(A.UserField1 AS DATETIME))) < @ProcessingDate

查询按预期工作。

奇怪的是,这个确切的代码曾经在SQL 2000中运行,但是我们已经迁移了系统以使用SQL 2008,现在我们遇到了这个问题。我在SQL 2000中遇到了一个问题,其中查询直接拒绝运行,除非日期时间相等条件是列表中的最后一个,所以一旦我们将它移动到列表的底部,它就能正常工作几个月。

我已经检查并仔细检查过,我看不出我给它的数据有什么问题,以及表格中的数据。我可以将UserField1中的每个值(这是nvarchar(256))转换为单独查询中的日期时间没问题。

我错过了什么吗?

表的架构非常大,所以我不会在这里发布整个内容,但它基本上归结为UserField1-20 nvarchar(256), nullTOWControlID int nullItemTypeEXT nvarchar(50), null

我还应该注意,如果我从sp_executesql语句中删除AND CAST(LTRIM(RTRIM(A.UserField1)) AS DATETIME) < @ProcessingDate,则查询会运行,但它无法获得正确的结果。

所有内容都指向表中的数据错误,但是如果我运行它:

declare @TOWControlID int = 9999,
        @ReportNum nvarchar = '6',
        @ProcessingDate datetime = '2015-03-24'
SELECT CAST(LTRIM(RTRIM(A.UserField1)) FROM GA_Item A
WHERE A.TOWControlID = @TOWControlID
      AND A.ItemTypeExt = 'PDF'
      AND A.UserField4 = 'Teller Report'
      AND A.UserField3 = @ReportNum
      AND A.UserField2 <> '9999'
      AND ISNULL(A.UserField5, 'N') = 'N'

查询执行正常。

2 个答案:

答案 0 :(得分:2)

您需要明确设置日期格式,请参阅https://msdn.microsoft.com/en-us/library/ms189491.aspx

升级到SQL2008后,默认语言是否发生了变化,请参阅

How to change the language and date format in SQL Server?

答案 1 :(得分:1)

进行子选择以获取转换日期,如果无法转换,则执行错误日期,然后与之进行比较

CASE 
WHEN ISDATE(LTRIM(RTRIM(A.UserField1))) = 1 
THEN CONVERT(datetime, LTRIM(RTRIM(A.UserField1))) 
ELSE @ProcessingDate END as convertedDate

and convertedDate < @ProcessingDate

似乎未指定where子句评估顺序。因此,其他条款应排除的非日期可以作为日期进行评估,除非排除条款恰好先运行

Using case statements with IsDate in a SQL where clause