【问题标题】:SQL Query for retreiving records that fall on the last day of the month用于检索一个月最后一天的记录的 SQL 查询
【发布时间】:2013-07-24 09:45:59
【问题描述】:

我有一张包含许多日期记录的表格。 我想执行一个查询,只返回该日期月份最后一天的记录。比如:

SELECT * FROM mytable
WHERE DATEPART(d, mytable.rdate) = DATEPART(d,DATEADD(m,1,DATEADD(d, -1, mytable.rdate)))

除非这不起作用,因为参数右侧的 rdate 应该是 dateadd 返回正确比较的月份的最后一天。

基本上有没有一种简洁的方法来进行这种比较? 等价的四分之一结束也很有帮助,但无疑更复杂。

编辑:

基本上我想检查给定日期是否是它所在月份(或季度)的最后一个日期。如果是,则返回该记录。这将涉及一些函数来返回任何日期的月份的最后一天。例如lastdayofmonth('2013-06-10') = 30(所以这条记录不会被返回。

EDIT2:

对于返回属于该季度最后一天的记录的情况,它们需要类似于:

SELECT * FROM mytable
WHERE DATEPART('d', mytable.rdate) = lastdayofmonth(mytable.rdate)
  AND DATEPART('m', mytable.rdate) = lastmonthofquarter(mytable.rdate);

棘手的一点是lastdayofmonth()lastmonthofquarter() 函数

【问题讨论】:

  • 一个月的最后一天总是比下个月的第一天早一天(在给定的年份)。
  • 是的,问题是如何在 SQL 中到达那里,最好不使用字符串操作

标签: sql date ms-access dateadd datepart


【解决方案1】:

使用DateSerial Function 计算给定日期该月的最后一天。

传递零作为第三个参数,day,实际上返回上一个月的最后日期。

rdate = #2013-7-24#
? DateSerial(Year(rdate), Month(rdate), 0)
6/30/2013 

因此,要获取 rdate 月份的最后日期,请将 1 添加到 month 参数中。

? DateSerial(Year(rdate), Month(rdate) + 1, 0)
7/31/2013 

您可能会怀疑这种方法在 12 月时会中断 rdate,因为 Month() + 1 会返回 13。但是,DateSerial 仍然可以应付。

rdate = #2013-12-1#
? DateSerial(Year(rdate), Month(rdate) + 1, 0)
12/31/2013 

如果您将从 Access 应用程序会话中运行查询,则可以基于该方法构建 VBA 函数,并在查询中使用自定义函数。

但是,如果查询将从 ODBC 或 OleDb 连接运行到 Access db,则查询不能使用 VBA 用户定义函数。在这种情况下,您可以直接在查询中使用DateSerial

SELECT m.*
FROM mytable AS m
WHERE m.rdate = DateSerial(Year(m.rdate), Month(m.rdate) + 1, 0)

如果您的 rdate 值都包含午夜作为时间组件,那应该可以工作。如果这些值包括其他时间,请使用DateValue

WHERE DateValue(m.rdate) = DateSerial(Year(m.rdate), Month(m.rdate) + 1, 0)

【讨论】:

  • 正是我所追求的。非常感谢。顺便说一句,这种方法仍然可以通过 PDO 上的准备查询来工作吗?我有一个查询我的 Access 数据库的 web 应用程序。
  • PDO 是 PHP 的 ODBC 访问,对吧?我认为从 ODBC 运行查询时 DateSerial 和其他日期函数仍然可用,但您必须检查。但是 ODBC 绝对排除了 VBA 用户定义的函数。
  • 是的,我相信它只是使用了 ODBC 驱动程序。我会写一个快速脚本并检查。
  • 刚刚发现季度版本的最后一天:只需将AND DatePart('m', m.rDate) In(3,6,9,12) 添加到WHERE 子句中即可。
  • 好的,如果这得到了你所需要的,另一种方法是Month(m.rDate) In(3,6,9,12) 它稍微简洁一些,但没有太大的改进。与我开始研究的方法相比,任何一种方法都比我开始研究的方法更简单。 :-)
【解决方案2】:

试试这个。

SELECT * FROM mytable
WHERE DATEPART(d, mytable.rdate) = 
DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, GETDATE()) + 1, 0))

【讨论】:

    【解决方案3】:

    试试这个,这是在MS Access上测试的:

    使用String Concatenation

    SELECT * FROM mytable
    WHERE 
    DatePart('d',mytable.rdate) = 
    DatePart('d',dateadd('m',1, "1/" & DatePart('m',mytable.rdate)  & "/" & DatePart('yyyy',mytable.rdate))-1);
    

    更新而不使用string concatenation

    SELECT * FROM
    (SELECT *,
    DATEPART('d',DATEDIFF('m',0,mytable.rdate)+1,
    DATEADD('m',1,
    DATEADD('d',DATEDIFF('d',0,mytable.rdate)- DATEPART('d',mytable.rdate)+1,0))-1) as EOMonth
    FROM mytable ) A
    WHERE DATEPART('d',mytable.rdate) = DATEPART('d',EOMonth)
    

    【讨论】:

    • 似乎只返回 1 条记录,总是从 2013 年 1 月 31 日开始
    • 您能在帖子中显示示例数据吗?是否要显示所有月末而不考虑当前日期的月末?
    • 恐怕我无法显示示例数据,但基本上有很多记录,而且它们都有不同的日期,有些在月底,有些只是任何一天。是的,我确实只想显示日期是该月最后一天的日期。当前日期的月末无关紧要。
    • 我实际上将您的原始答案修改为您的编辑(将 now() 替换为 rdate 但它不起作用
    • @harryg:我认为这是正确的,只是我的格式是 mm/dd/yyyy,而你的格式可能是 dd/mm/yyyy。所以,在这方面,如果我是正确的,我会改变我对你的格式的回答。所以,用我的第二个代码再试一次。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-14
    • 1970-01-01
    • 1970-01-01
    • 2018-10-08
    相关资源
    最近更新 更多