【问题标题】:SQL Date Search without time没有时间的 SQL 日期搜索
【发布时间】:2009-02-13 21:10:48
【问题描述】:

我有一个按日期搜索的查询。数据库中的日期包括时间。如何仅搜索日期。

select * 
from weblogs.dbo.vwlogs 
where Log_time between @BeginDate and @EndDAte 
  and (client_user=@UserName or @UserName  Is null) 
order by Log_time desc

cmd.Parameters.AddWithValue("@BeginDate", txtBeginDate.Text);
cmd.Parameters.AddWithValue("@EndDAte", txtEndDate.Text);

【问题讨论】:

    标签: asp.net sql-server


    【解决方案1】:

    让你的 sql 保持原样,只修复你的参数:

    cmd.Parameters.Add("@BeginDate", SqlDbType.DateTime).Value =
        DateTime.Parse(txtBeginDate.Text).Date;       
    cmd.Parameters.Add("@EndDAte", SqlDbType.DateTime).Value =
        // add one to make search inclusive
        DateTime.Parse(txtEndDate.Text).Date.AddDays(1);  
    

    您还想首先检查以确保您的文本框是有效的日期时间,但您应该明白这一点。

    这里唯一需要注意的是,由于 BETWEEN 运算符的怪癖,它将匹配第二天的第一时刻。因此,为了解决这个问题,我们编写如下查询:

    SELECT * 
    FROM vwlogs 
    WHERE Log_time >= @BeginDate AND Log_Time < @EndDate 
        AND (client_user=@UserName OR @UserName IS NULL) 
    ORDER BY Log_time DESC
    

    特别注意日期前后的比较运算符。

    【讨论】:

    • 我收到此错误“当前上下文中不存在名称 'SqlDbTypes'。”
    • 糟糕:它只是 SqlDbType,没有 's'。这就是我直接在回复窗口中输入而不是先通过 Visual Studio 得到的结果。修复了帖子。
    • 顺便说一句,您应该始终使用显式类型:让 .Net 推断您想要的参数类型可能会导致难以发现的性能问题。
    【解决方案2】:

    首先要做的是从日期中删除时间。如果您想在 sql server 代码中执行此操作,您可以使用类似下面的代码。我在我工作的所有数据库上都有这个功能

    cast(floor(cast(@fromdate as float)) as datetime)
    

    接下来要担心的是 where 条件。您需要确保选择从开始日期开始到结束日期的所有内容。您还需要确保一天的查询可以使用,您可以使用这样的日期添加来完成

    Where LogTime >= @fromdate and LogTime < DateAdd(dd, 1, @todate)
    

    【讨论】:

      【解决方案3】:

      在 SQL 中,将开始和结束日期舍入到整个日期并使用 >= @BeginDate 并且非常具体地使用

      例如

      SELECT @BeginDate = DATEADD(Day, DATEDIFF(Day, 0, @BeginDate), 0),
             @EndDAte = DATEADD(Day, DATEDIFF(Day, 0, @EndDAte) + 1, 0)
      
      select * 
      from weblogs.dbo.vwlogs 
      where     Log_time >= @BeginDate 
            and Log_time < @EndDAte
            and (@UserName Is null OR client_user=@UserName)
      order by Log_time desc
      

      请注意,我首先移动了“@UserName Is null”,因为有一些证据表明该测试很容易通过/失败,并且会导致第二个 CPU 密集型测试 (client_user=@UserName) 在以下情况下被忽略第一个测试是 TRUE(当然可能是 TommyRot ...)

      另外,为了获得最佳性能,您应该明确命名您需要的所有列,而不是使用“SELECT *”(但这可能只是为了解决这个问题)

      【讨论】:

      • @username 参数的顺序无关紧要:优化器应该弄清楚它并在需要时重新排序。
      • 从技术上讲,这是“确定”日期,而不是“四舍五入”。 stackoverflow.com/questions/85373/floor-a-date-in-sql-server
      • 谢谢。我的意思是将“@EndDate”设置为 Midnight FOLLOWING,而不是之前。我已经编辑了我的帖子
      【解决方案4】:

      如果你想改sql,

      TRUNC(Log_Time) 将每个日期时间减少到该日期的午夜。

      确保将列上的索引构建为 TRUNC(Log_TIME) 以便它可用。

      【讨论】:

        【解决方案5】:

        另一个问题 - 截断结束日期将不包括该日期!考虑:

        WHERE Log_Time >= @BeginDate AND Log_Time

        如果@EndDate 被截断,它将是午夜并且当天不匹配任何内容。您需要增加一天!

        【讨论】:

          【解决方案6】:

          通过在查询前添加以下行来清理日期...

          select 
              @begindate=dateadd(day,datediff(day,0,@begindate),0),
              @enddate=dateadd(ms,-3,dateadd(day,datediff(day,0,@enddate),1))
          

          这会将您的开始日期限制到可能的最低时间(00:00:00.000),并将结束日期限制到可能的最高时间(23:59: 59.997)。然后,您可以将 BETWEEN 查询保持原样。

          select * 
          from weblogs.dbo.vwlogs 
          where Log_time between @BeginDate and @EndDAte 
          and (client_user=@UserName or @UserName Is null) 
          order by Log_time desc
          

          希望这会有所帮助。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-02-16
            • 2018-08-28
            • 2013-10-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多