SQL - 在 WHERE 子句中使用日期范围的结果集中未显示正确日期

Posted

技术标签:

【中文标题】SQL - 在 WHERE 子句中使用日期范围的结果集中未显示正确日期【英文标题】:SQL - Correct dates not being presented in result set with date ranges in WHERE clause 【发布时间】:2021-11-27 12:55:42 【问题描述】:

没有 where 子句的结果集显示有 9 月 30 日的数据,当使用下面的 where 子句时,结果集中没有出现第 30 个数据(结果集见下图)- 我的主要目的是显示上个月第一天和上个月最后一天之间的数据 - 非常感谢任何帮助:

SQL 查询

DECLARE @date1 datetime
DECLARE @date2 datetime
SET @date1 = getdate()
SET @date2 = getdate()-15 -- reason for less 15 days is because this will only be run within the first 15 days 
                          -- of the current month, it will enable me to get the last day of the previous 
                          -- month even if I run the SQL in the next month.

SELECT
        A.TA_SEQ as 'WO No',
        A.TA_DUE_DATEUTC

FROM 
        F_TASKS A WITH (NOLOCK)
        INNER JOIN FINFILE B WITH (NOLOCK) ON A.TA_FKEY_IN_SEQ = B.IN_SEQ 
        INNER JOIN InstructionSetGroups C WITH (NOLOCK) ON B.InstructionSetGroupId = C.InstructionSetGroupId 

WHERE
        A.TA_TASK_DESC = 'BREAKDOWN' AND
        A.TA_STATUS IN ('ACTIVE', 'ASSIGNED', 'COMPLETE', 'HISTORY') AND
        A.TA_DUE_DATE >= DATEADD(DAY, 1, EOMONTH(@date1, -2)) AND
        A.TA_DUE_DATE <= EOMONTH(@date2) 

ORDER BY 
        A.TA_DUE_DATE desc

结果集

在 where 子句中使用日期范围的结果集:

在 where 子句中不使用日期范围的结果集 - 正如您所见,也有很多 30 日的数据没有被捕获

【问题讨论】:

在将日期范围与时间组件进行比较时,我建议使用包含的开始日期和不包含的结束日期。尝试在结束日期上添加一天并将运算符更改为小于:A.TA_DUE_DATE &lt; DATEADD(day, 1, EOMONTH(@date2)) 停止到处乱喷NOLOCK,这不是一个g-faster开关,而是一个给出不正确结果的开关 你得到的数据是正确的。例如datetime 2021-09-30 00:00:00.003 不等于或小于 2021-09-30,它大于它(1/300 秒)。 【参考方案1】:

我会采用不同的方法来处理您的日期值。整个 -15 的东西很奇怪,并且会在接近月底的日子里引起问题。如果您了解一些日期数学,则使用单个变量就足够了。

DECLARE @date1 date --use the data datatype here because time is important in this case
SET @date1 = getdate()

--this is to show you the values and can be removed.
select BeginningOfLastMonth = dateadd(month, datediff(month, 0, @date1) - 1, 0)
    , BeginningOfCurrentMonth = dateadd(month, datediff(month, 0, @date1), 0)

--Your select statement here
where A.TA_DUE_DATE >= dateadd(month, datediff(month, 0, @date1) - 1, 0)
        A.TA_DUE_DATE <= dateadd(month, datediff(month, 0, @date1), 0) --ANY datetime value less than this is before the end of last month

【讨论】:

是的!但为什么不DATEFROMPARTS? So much tidier. @AaronBertrand 好点。旧习惯很难改掉,不是吗?已经保存了多年的各种奇怪的约会数学资料。 他们确实如此,多年来我将数据类型放在大写字母中并且很难改掉这个习惯,也无法摆脱像 RTRIM 这样的懒惰速记,因为 toString 比一个合适的CONVERT【参考方案2】:

EOMONTH 非常模棱两可,因为它返回一个月的最后一天午夜。我在Will you use EOMONTH()?谈为什么我不喜欢这个功能

如果您想要整个上个月,有比假设代码将在前 15 天内运行更简单、更安全的方法:

DECLARE @ThisMonth date = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1);

SELECT ... FROM ...
  WHERE TA_DUE_DATE >= DATEADD(MONTH, -1, @ThisMonth)
    AND TA_DUE_DATE <  @ThisMonth;

我解释了为什么DATEFROMPARTS 最适合Simplify Date Period Calculations in SQL Server 中的此类工作。

剩下的,我们从哪里开始?

getdate()-15 是一种懒惰、不直观的简写,在其他情况下会中断。请使用DATEADD(DAY, -15, GETDATE()) 并查看Bad Habits to Kick : Using shorthand with date/time operations。

您可以以比每个声明的显式行更易读的方式声明/设置,并为每个集合再次声明/设置:

 DECLARE @date1 datetime = GETDATE(),
         @date2 datetime = DATEADD(DAY, -15, GETDATE());

as 'WO No' - 请使用 AS [Wo No]AS "Wo No" - 字符串分隔符使这些别名看起来像字符串,并且该语法的某些形式已被弃用。

请always specify the schema和never use meaningless aliases like A, B, C

&gt;= AND &lt;=BETWEEN 相同。我谈论为什么BETWEEN 对于What do BETWEEN and the devil have in common? 中的日期范围总是一个糟糕的主意

NOLOCKI'm using NOLOCK; is that bad? 上的大量资源

Dating responsibly 中的一般约会提示

【讨论】:

以上是关于SQL - 在 WHERE 子句中使用日期范围的结果集中未显示正确日期的主要内容,如果未能解决你的问题,请参考以下文章

如何在 WHERE 子句中使用混合文本和日期字段?

在 where 子句 SQL 中的 case 语句中使用参数

如何在 SQL Server 2008 的 where 子句中仅比较日期并忽略时间

SQL语句怎样查询一个范围

在 WHERE IN 子句 SQL 中显示每条记录的 MAX 日期

Oracle SQL Where 子句查找超过 30 天的日期记录