【问题标题】:Stored Procedure and C# SqlDataReader Returns Less Rows Than Expected存储过程和 C# SqlDataReader 返回的行数少于预期
【发布时间】:2014-03-20 13:49:00
【问题描述】:

有人要求我将网站应用程序从一台服务器迁移到另一台服务器。 代码是以前的开发者写的。

他使用以下内容创建了一个存储过程: [参数]

            @SurveyPeriodConfigID int = -1,
            @StartDate DATETIME = NULL,
            @EndDate DATETIME = NULL,
            @StartTime DATETIME = [9:00:00],
            @EndTime DATETIME = [19:00:00],
            @Category INT = -1,
            @SubcategoryID INT = -1,
            @ReportType VARCHAR(50) = null,
            @DepartmentID INT = -1,
            @FloorID INT = -1,
            @RoomID INT = -1,
            @IsLazyLoad BIT = 0,
            @Day INT = -1

和 [WHERE 原因]:

            SELECT [fields]
            FROM [tables]
            WHERE 
            (DATEPART(dw, rsdm.DateCreated)) != 7 AND (DATEPART(dw, rsdm.DateCreated)) !=1
                    AND rsdm.DateCreated BETWEEN @StartDate AND @EndDate
                    AND (CONVERT(VARCHAR(8),rsdm.DateCreated,108) BETWEEN @StartTime AND @EndTime)
                    AND (@Category = -1 OR rsdm.CategoryCodeID = @Category)
                    AND (@SubcategoryID = -1 OR rsdm.SubcategoryID = @SubcategoryID)
                    AND (@DepartmentID =-1 OR rsdm.DepartmentID = @DepartmentID)
                    AND (@FloorID =-1 OR rsdm.FloorID = @FloorID)
                    AND (@RoomID =-1 OR rsdm.RoomID = @RoomID)
                    AND (@Day =-1  OR  DATEPART(dw, rsdm.DateCreated) = @Day)

C#代码:

            SqlDataReader sqlDataReader = thisCommand.ExecuteReader(CommandBehavior.CloseConnection);

...调用存储过程并返回SqlDataReader。

到目前为止一切顺利。

现在问题...以前旧网站返回 8200 行,但现在新网站返回 6500 行!!!

我在我的 sql 数据库副本上设置了我的 PC 上的代码和网站...它返回正确的值 8200。然后我将 web.config 更改为指向新网站 sql server...6500 行!!!

我备份了现场 sql 数据库并在我的 PC 上本地恢复了相同的数据库并对其进行了测试...... 8200 行!!!

旧站点有 Sql server 2005,我的 PC 有开发人员 SQL 2012,而实时服务器有 SQL 2012。

然后我在新站点 Sql Server 上运行 sql profiler,提取脚本并在同一个 sql 数据库 8200 条记录上运行脚本!!!

我在过去的 1-2 天里一直在研究这个问题,但仍然不知道为什么实时 Sql Server 通过 sqldatareader 返回 6500 行。

任何建议将不胜感激。

【问题讨论】:

  • 很抱歉,没有实际数据几乎不可能回答这个问题。
  • CS/CI(区分大小写)设置是否相同? ansi-null 默认值是否相同?
  • OK 希望有人会说这是 SqlDataReader 中的一些东西,我错过了一些东西。我检查了数据,似乎没有问题。
  • 开始删除 where 子句,看看你最终能不能得到数据,然后再次添加它们,你就会发现哪里出错了
  • 你为什么使用CONVERT(VARCHAR(8),rsdm.DateCreated,108) BETWEEN @StartTime AND @EndTime?通过字符串投射日期绝不是一个好主意;那里的意图是什么? (注意这有两种强制转换——一种是隐式的,一种是显式的——不好)

标签: c# sql-server tsql sqldatareader


【解决方案1】:

我会检查不同服务器上的选项配置是否不同,特别是 ANSI_NULLS(参见下面的脚本)。请注意,当您在 SSMS 中运行脚本时,默认选项可能与使用 ADO.NET 时有效的选项不同(请参阅 SSMS 工具/选项/查询执行/SQL Server/ANSI)。这通常可以解释 SSMS 和 ADO.NET 之间的行为差​​异。

DECLARE @options INT 
SELECT @options = @@OPTIONS 

PRINT @options
IF ( (1 & @options) = 1 ) PRINT 'DISABLE_DEF_CNST_CHK' 
IF ( (2 & @options) = 2 ) PRINT 'IMPLICIT_TRANSACTIONS' 
IF ( (4 & @options) = 4 ) PRINT 'CURSOR_CLOSE_ON_COMMIT' 
IF ( (8 & @options) = 8 ) PRINT 'ANSI_WARNINGS' 
IF ( (16 & @options) = 16 ) PRINT 'ANSI_PADDING' 
IF ( (32 & @options) = 32 ) PRINT 'ANSI_NULLS' 
IF ( (64 & @options) = 64 ) PRINT 'ARITHABORT' 
IF ( (128 & @options) = 128 ) PRINT 'ARITHIGNORE'
IF ( (256 & @options) = 256 ) PRINT 'QUOTED_IDENTIFIER' 
IF ( (512 & @options) = 512 ) PRINT 'NOCOUNT' 
IF ( (1024 & @options) = 1024 ) PRINT 'ANSI_NULL_DFLT_ON' 
IF ( (2048 & @options) = 2048 ) PRINT 'ANSI_NULL_DFLT_OFF' 
IF ( (4096 & @options) = 4096 ) PRINT 'CONCAT_NULL_YIELDS_NULL' 
IF ( (8192 & @options) = 8192 ) PRINT 'NUMERIC_ROUNDABORT' 
IF ( (16384 & @options) = 16384 ) PRINT 'XACT_ABORT'

【讨论】:

  • 5496 ANSI_WARNINGS ANSI_PADDING ANSI_NULLS ARITHABORT QUOTED_IDENTIFIER ANSI_NULL_DFLT_ON CONCAT_NULL_YIELDS_NULL 在两个 Sql 2012 服务器上
  • @Rob 您需要分别从 SSMS 和 SqlClient 运行它,针对单独两个服务器 - 重点是要找到 有什么不同。 SSMS 不使用与SqlClient 相同的默认值(实际上,SSMS 选项取决于您自己在 SSMS 中的用户特定选项)
【解决方案2】:

当您连接到数据库时,总会有一个与之关联的登录帐户。您的应用程序使用的登录名是否与连接 SQL Server Management Studio 时使用的登录名不同?日期格式基于您登录的默认语言。

请运行以下查询:

Select  syslogins.name, syslogins.language, syslanguages.dateformat
From    sys.syslogins
        Inner Join sys.syslanguages
            On syslogins.language = syslanguages.name

检查返回的所有登录的日期格式列。如果日期格式不同,那么这可能解释了为什么从应用程序运行与从 SSMS 运行时会得到不同的结果。

如果这确实是您的问题的原因,那么您可以按照此博客中的说明更改登录的默认语言:http://blogs.lessthandot.com/index.php/datamgmt/datadesign/setting-a-standard-dateformat-for-sql-se/

【讨论】:

  • 谢谢!!!选择 syslogins.name, syslanguages.datefirst 从 sys.syslogins 内加入 sys.syslanguages 上 syslogins.language = syslanguages.name ...帮助!!!
【解决方案3】:

既然你提到SSMS和SqlClient的结果不同,我能想到的有两个选择

  • 实际上在不同的模式中有 2 个不同的存储过程,SSMS 选择一个,SqlClient 另一个(大概基于身份)
  • (更有可能)SET 选项不同,导致不同的行为

要检查后者,请在 SSMS 和 SqlClient 中运行 select @@OPTIONS,然后进行比较。此处列出了标志:http://www.mssqltips.com/sqlservertip/1415/determining-set-options-for-a-current-session-in-sql-server/

【讨论】:

  • 好的,谢谢。 5496 SSMS,5492 SqlClient。现在怎么办?两者有什么不同?
【解决方案4】:

好的,问题出在(DATEPART(dw, rsdm.DateCreated)) != 7 AND (DATEPART(dw, rsdm.DateCreated)) !=1

SqlClient 用户将 DATEFIRST 设置为 1,而我的 SSMS 为 7。与其他 sql server 实例的所有其他相同用户连接都将 DATEFIRST 设置为 7。(还要感谢 @"G Mastros" 对问题的最终确认)。

我现在所做的只是添加 SQL 脚本 SET DATEFIRST 7; 并将处理为什么用户稍后设置为 1!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-09
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-06
    相关资源
    最近更新 更多