【问题标题】:SqlDateTime overflow on join. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM连接时 SqlDateTime 溢出。必须在 1753 年 1 月 1 日上午 12:00:00 到 9999 年 12 月 31 日晚上 11:59:59 之间
【发布时间】:2017-08-03 15:57:48
【问题描述】:

我有一个视图 (vw_users) 和一个表 (CTUsers)。当我从视图中请求数据时,我的 sql 查询曾经正常工作:

var result = (from i in dc.vw_Users
              where i.CTid == ctid 
              select new 
              { 
                  UserId = i.UserId,  
                  WelcomeSent = (i.WelcomeSent != null && i.WelcomeSent.ToString().Length > 0 
                                ? DateTime.Parse(i.WelcomeSent.ToString()) 
                                 : new DateTime())
              });

但现在我想从表中获取 WelcomeSent,所以我使用以下代码:

var result = (from i in dc.vw_Users 
              join k in dc.CTUsers 
              on i.CTid equals k.CTid 
              where i.CTid == ctid 
              select new 
              { 
                  UserId = i.UserId, 
                  WelcomeSent = (k.WelcomeSent != null && k.WelcomeSent.ToString().Length > 0 
                                 ? DateTime.Parse(k.WelcomeSent.ToString()) 
                                 : new DateTime()) 
              }).Distinct();

但是现在当我运行这个查询时,我得到了这个错误:

SqlDateTime 溢出。必须在 1753 年 1 月 1 日凌晨 12:00:00 到 12/31/9999 晚上 11:59:59

SQL 视图和表 WelcomeSent 类型为 DateTime,也可以为 NULL。这是 WelcomeSent 的示例值:2017-03-07 00:00:00.000

【问题讨论】:

  • 你知道visual studio支持多行吗?!
  • 我不明白这条评论的相关性
  • 稍微格式化您的代码将帮助您获得答案。对于任何回答者来说,阅读关于完全未知问题的 879 字符行都非常困难。上面的评论真的很相关。
  • 我几乎想花时间格式化它,但它太多了
  • 然后把空的new DateTime改成new DateTime(1753,1,1)

标签: c# sql join


【解决方案1】:

这里真正的问题是Distinct() 方法。如果您掌握了以 SQL 格式运行的查询并直接在 SSMS 的数据库上运行,它们将运行良好。 LINQ to SQL 的限制是在使用 Distinct() 时不允许 DateTime 值小于某个值。

我不确定你为什么需要在日期时间和字符串值之间使用奇怪的来回转换。

以下是在数据库上运行的实际查询。

第一种情况:

SELECT [t0].[Id] AS [TokenId], [t0].[Token],     
(CASE WHEN ([t0].[ExpiryDate] IS NOT NULL) 
            AND ((CONVERT(Int,LEN(CONVERT(NVarChar(MAX),[t0].[ExpiryDate])))) > @p1) 
        THEN 1        
      WHEN NOT (([t0].[ExpiryDate] IS NOT NULL) 
            AND ((CONVERT(Int,LEN(CONVERT(NVarChar(MAX),[t0].[ExpiryDate])))) > @p1)) 
        THEN 0 
      ELSE NULL     
 END) AS [value], 
 CONVERT(NVarChar(MAX),[t0].[ExpiryDate]) AS [s] 
 FROM [dbo].[TokenView] AS [t0]WHERE [t0].[Id] = @p0

第二种情况:

SELECT DISTINCT [t2].[Id] AS [TokenId], [t2].[Token], [t2].[value], [t2].[value2] AS [s], [t2].[value3]
FROM (    
    SELECT [t0].[Id], [t0].[Token], 
    (CASE WHEN ([t1].[ExpiryDate] IS NOT NULL) 
                AND ((CONVERT(Int,LEN(CONVERT(NVarChar(MAX),[t1].[ExpiryDate])))) > @p0) 
            THEN 1            
          WHEN NOT (([t1].[ExpiryDate] IS NOT NULL) 
                    AND ((CONVERT(Int,LEN(CONVERT(NVarChar(MAX),[t1].[ExpiryDate])))) > @p0))
            THEN 0            
          ELSE NULL         
    END) AS [value], 
    CONVERT(NVarChar(MAX),[t1].[ExpiryDate]) AS [value2], @p1 AS [value3]    
FROM [dbo].[TokenView] AS [t0]    
    INNER JOIN [dbo].[Tokens] AS [t1] ON [t0].[Id] = [t1].[Id]) AS [t2]
WHERE [t2].[Id] = @p2

我建议对第二个查询使用以下解决方案来解决问题。

创建一个可以保存您使用查询从数据库中选择的数据的类。

public class MyClass
{
    public int Id { get; set; }

    public string Token { get; set; }

    //Consider this property as WelcomeSent property from your code.
    public DateTime? ExpiryDate { get; set; }

    //Use this property only to display the data in UI.
    public DateTime FormattedExpiryDate
    {
        get
        {
            return ExpiryDate != null && ExpiryDate.ToString().Length > 0
                                        ? DateTime.Parse(ExpiryDate.ToString())
                                         : new DateTime();
        }
    }
} 

如下更改查询。

var query = (from i in dc.TokenViews //TokenViews is same as vw_Users of yours.
                     join k in dc.Tokens //Tokens is same as CTUsers
                     on i.Id equals k.Id
                     where i.Id == 5 //Hardcoding the selection criteria. 
                     select new MyClass
                     {
                         Id = i.Id,
                         Token = i.Token,
                         ExpiryDate = k.ExpiryDate //Retrieving values as it is from the db.
                      }).Distinct();

显示如下值,看看ExpiryDate和FormattedExpiryDate的区别

foreach (var item in query)
{
    Console.WriteLine("Id : {0}", item.Id);
    Console.WriteLine("Token : {0}", item.Token);
    Console.WriteLine("ExpiryDate : {0}", item.ExpiryDate);
    Console.WriteLine("FormattedDate : {0}", item.FormattedExpiryDate);
}

您也可以对第一个查询使用相同的方法。这将避免 SQL 查询中的所有CASE WHEN 子句和CONVERTs。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多