【问题标题】:SQL Selecting all data between date ranges when date is stored as nvarchar当日期存储为nvarchar时,SQL选择日期范围之间的所有数据
【发布时间】:2016-12-24 13:28:28
【问题描述】:

我继承了一个 T-SQL 表,其中 Start_DateEnd_Date 列是 nvarchar 数据类型。我需要选择开始日期早于该日期但结束日期晚于该日期的特定日期的所有记录。

另一个问题是有些人仍然是最新的并且没有end_date。可悲的是,我不能只将列的数据类型转换为日期。我想用 VBA 写这个,因为

  1. 我的老板懂 Excel,而且
  2. 他正在做的报告必须以 Excel 格式发送

例如:

Name    Start_Date    End_Date
Joe     12/1/2014     6/15/2016
Bob     8/28/2013     6/5/2014
Jon     1/27/2015     12/18/2015
Tim     8/28/2013     

如果我选择的日期是 8/15/2015,我返回的数据应该是

Name    Start_Date    End_Date
Joe     12/1/2014     6/15/2016
Jon     1/27/2015     12/18/2015
Tim     8/28/2013     

我尝试了以下查询,但它们返回 Run-time error -2147217900 (80040e14) Automation error

SELECT NAME 
FROM INFORMATION 
WHERE CONVERT(datetime, START_DATE, 101) >= '12/1/2015' 
  AND CONVERT(datetime, END_DATE, 101) <= '12/31/2015'

SELECT NAME 
FROM INFORMATION 
WHERE START_DATE >= '12/1/2015'

编辑: 我正在使用以下代码来构建我的查询:

For intYear = Year(Now()) To 2012 Step -1
    For intMonth = 12 To 1 Step -1
        FirstDayOfMonth = DateSerial(intYear, intMonth, 1)
        LastDayOfMonth = DateSerial(intYear, intMonth + 1, 0)
        SQL = "SELECT NAME FROM dbo.INFORMATION " & _
              "WHERE CONVERT(DATETIME, START_DATE, 101) <= " & FirstDayOfMonth & " AND " & _
              "CASE END_DATE WHEN '' THEN GETDATE() " & _
              "ELSE CONVERT(DATETIME, END_DATE, 101) END >= " & LastDayOfMonth
        Debug.Print SQL
        'Output:
        'SELECT NAME FROM dbo.INFORMATION WHERE CONVERT(DATETIME, START_DATE, 101) 
        '<= 12/1/2016 AND CASE END_DATE WHEN '' THEN GETDATE() ELSE 
        'CONVERT(DATETIME, END_DATE, 101) END >= 12/31/2016
        Set rs = cn.Execute(SQL)
    Next intMonth
Next intYear

更新 2:

我将SQL 设置为文字查询,而不是动态生成它并进行错误捕获(我早就应该这样做了)。我认为在日期周围加上单引号会导致它成为字符串而不是日期,但我尝试了两种方式。

SQL = "SELECT EMPLOYEE_NAME FROM dbo.INFORMATION " & _
      "WHERE CONVERT(DATETIME, START_DATE, 101) <= 12/01/2016 " & _
      "AND CASE END_DATE " & _
      "WHEN '' THEN GETDATE() " & _
      "ELSE CONVERT(DATETIME, END_DATE, 101) " & _
      "END >= 12/31/2016"

无论有无单引号,SSMS 的实际 SQL 错误都是:

Msg 241, Level 16, State 1, Line 4
Conversion failed when converting date and/or time from character string.

查看表中的数据,我可以看到有些日期是NULL,有些是空白,有些是mm/dd/yy(甚至是m/d/yy)。我希望 SQL 来完成所有繁重的工作,但现在我正在尝试确定 SELECT * 是否会更难并在 Excel 中处理它,或者让我的老板、他的同事和我的老板来“修复”表格.

【问题讨论】:

  • 在您的 VBA SQL 构造字符串中,您可能需要在日期文字周围添加单引号字符,并可能在日期值上使用格式函数以确保将 VBA 日期正确格式化为 ' mm/dd/yyyy' 字符串。

标签: sql sql-server vba sql-server-2008 date


【解决方案1】:

您需要切换 >= 和

不过,您走在正确的轨道上。当您说要在 VBA 中执行此操作时,我会提醒您不要在 VBA 中执行任何逻辑。在 SQL 中进行所有过滤,然后使用 VBA 调用 SQL。另外,不要忘记您可以将 Excel 直接连接到 SQL 作为数据源并跳过 VBA。

无论如何,您的 SQL 查询应该如下所示:

SELECT  Name
FROM    dbo.INFORMATION
WHERE   CONVERT(DATETIME, Start_Date, 101) <= @targetdate
        AND CONVERT(DATETIME, End_Date, 101) >= @targetdate

但是你有一个没有结束日期的人的情况。让我们修复它,以便它适合一个查询。

SELECT  Name
FROM    dbo.INFORMATION
WHERE   CONVERT(DATETIME, Start_Date, 101) <= @targetdate
                    AND     CASE End_Date
                              WHEN '' THEN GETDATE()
                              ELSE CONVERT(DATETIME, End_Date, 101)
                            END >= @targetdate

如果他们有结束日期,我们将使用他们的结束日期,如果没有,我们现在使用。如果您的目标日期可能在未来,那么您可以使用任意大的日期。

最后一项是使其更具可读性,使用 BETWEEN:

SELECT  Name
FROM    dbo.INFORMATION
WHERE   @targetdate BETWEEN CONVERT(DATETIME, Start_Date, 101)
                    AND     CASE End_Date
                              WHEN '' THEN GETDATE()
                              ELSE CONVERT(DATETIME, End_Date, 101)
                            END

【讨论】:

  • &gt;=&lt;= 非常受欢迎...为此 +1!但是,我仍然收到自动化错误。请查看我的编辑。
  • 这是一个VBA错误,不幸的是我对VBA一无所知。您是否有权直接查询 SQL?我建议通过 SQL Management Studio 确认查询是否有效,然后更改您的 VBA 代码以执行一些简单的操作,例如从信息中选择前 10 个名称,我的猜测是您会得到相同的错误,因为它可能与任何特定的无关SQL 查询。
  • 如果我的数据更干净,你的查询会很棒。你有没有机会知道我可以如何处理日期的可变性?
  • 哎呀。是的,理想情况下你会修复数据。一种简单的方法是将其以正确的格式复制到新表中,然后从新表中进行选择。如果出现问题,您仍然可以使用旧桌子。另一种选择是表格上的视图,在视图中,您可以使用一堆 case 语句修复日期(基本上,如果它是 mm/dd/yyyy,则使用 101 进行转换,如果 mm/dd/yy 使用 1,等等)。见sqlusa.com/bestpractices/datetimeconversion。这样,您的 VBA 查询就很简单,而视图是一次性复杂项目。
  • 有趣的花絮:其中一个日期是 605 年 9 月 2 日(我确定它应该是 05 年 9 月 2 日或 06 日)。 VBA 将其识别为有效日期并可以正常使用。但是,如果您尝试将该值插入到格式化为日期的单元格中,Excel 会崩溃。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-21
相关资源
最近更新 更多