1

我正在编写一个应该根据日期范围进行计数的 SQL 语句。但是,由于某种原因,没有返回数据。在我尝试使用我的日期范围过滤计数之前,一切正常。这是那个代码。

SELECT
CR.GCR_RFP_ID
,S.RFP_RECEIVED_DT
,CR.GCR_RECEIVED_DT
,CT.GCT_LOB_IND
FROM ADM.GROUP_CHANGE_TASK_FACT CT
JOIN ADM.B_GROUP_CHANGE_REQUEST_DIM CR 
    ON CR.GROUP_CHANGE_REQUEST_KEY = CT.GROUP_CHANGE_REQUEST_KEY 
JOIN ADM.B_RFP_WC_COVERAGE_DIM S 
    ON S. RFP_ID = CR.GCR_RFP_ID
WHERE CT.GCT_LOB_IND = 'WC'
AND CR.GCR_CHANGE_TYPE_ID IN ('10','20','30','50','60','70','80','90','100','110',
                          '120','130','140', '150','160','170','180','190','200',
                          '210','220','230','240','260','270','280','300','310',
                          '320','330','340','350','360','370','371','372')
AND S.RFP_AUDIT_IND = 'N'
AND S.RFP_TYPE_IND = 'A'

我使用的日期字段称为 CR.GCR_RECIEVED_DT。这是数据库中的一个新字段 a,所有记录都是 01-JAN-00。但我仍在进行计数,以确保我可以获取数据。现在,我添加了这一行:

AND CR.GCR_RECEIVED_DT LIKE '01-JAN-00'

就像随机测试一样。我知道所有的日期都是一样的。它工作正常,没有问题。因此,我删除了该行并将其替换为:

AND CR.GCR_RECEIVED_DT BETWEEN '31-DEC-99' AND '02-JAN-00'

我使用这个小范围来保持简单。但即使 01-JAN-00 明确地落在这两个日期之间,也不会返回任何数据。我不知道为什么会这样。我什至试过这条线:

AND CR.GCR_RECEIVED_DT = '01-JAN-00'

而且我仍然没有返回数据。它似乎只适用于 LIKE。我已经检查过,该字段是日期类型。任何帮助将不胜感激。

4

2 回答 2

3

如果您NLS_DATE_FORMAT设置为,DD-MON-YY则可以解释前两个结果之间的明显差异。

当您使用LIKE它时,使用默认格式模型将左侧的日期值隐式转换为字符串进行比较,然后将其与固定字符串进行比较;'01-JAN-00'就像'01-JAN-00'。_ 你正在有效地做:

AND TO_CHAR(CR.GCR_RECEIVED_DT, 'DD-MON-YY') LIKE '01-JAN-00'

不过LIKE,用来比较日期并没有任何意义。但是,当您使用BETWEEN时,左侧将保留为日期,因此您实际上是在执行以下操作:

AND CR.GCR_RECEIVED_DT BETWEEN TO_DATE('31-DEC-99', 'DD-MON-YY')
  AND TO_DATE('02-JAN-00', 'DD-MON-YY')

...并且是2099TO_DATE('31-DEC-99', 'DD-MON-YY')年12 月 31日,而不是 1999 年。仅当第一个值低于第二个值时才有效(来自文档,'如果 expr3 < expr2,则间隔为空')。因此,您正在寻找 2099 和 2000 之间的值,这将始终为空。如果您的日期模型是,来自 NLS 参数或显式通过,那么它将查找 1999 到 2000 之间的值,并找到您的记录。BETWEENDD-MON-RRTO_DATE

您的第三个结果更具推测性,但表明您所在GCR_RECEIVED_DT领域的值具有时间成分,或者不是您认为的世纪。这与LIKE版本类似,只是这次将固定字符串转换为日期,而不是将日期转换为字符串;有效:

AND CR.GCR_RECEIVED_DT = TO_DATE('01-JAN-00', 'DD-MON-YY')

如果他们在午夜,2000-01-01这将起作用。因为这并不意味着它们是在午夜之后的某个时间,或者更有可能——因为你在现有记录中使用了一个“神奇”的日期——它们完全是另一个日期,很可能1900-01-01

这是刚刚过去的午夜1900的 SQL Fiddles 。


如果该字段最终将具有新记录的时间组件,您可能希望像这样构建条件,并使用日期文字更清晰(IMO):

AND CR.GCR_RECEIVED_DT >= DATE '2000-01-01'
AND CR.GCR_RECEIVED_DT < DATE '2000-01-02'

这将在任何时间找到任何记录2000-01-01,并且可以使用该列上的索引(如果可用)。BETWEEN是包容性的,因此 usingBETWEEN DATE '2000-01-01' AND '2000-01-02'将包括您可能不想要的任何在晚些时候恰好在午夜的记录。

无论您最终做什么,都避免依赖隐式转换,NLS_DATE_FORMAT因为有一天它可能不会设置为您期望的值,从而导致潜在的数据损坏或难以发现的错误;如果可以避免歧义,请在模型中指定完整的四位数年份。

于 2013-08-28T16:50:35.707 回答
1

尝试这样的事情:

WHERE TRUNC(CR.GCR_RECEIVED_DT) = TO_DATE('01-JAN-00','DD-Mon-YY')

不带参数的 TRUNC 从 DATE 中删除小时、分钟和秒。

于 2013-08-28T15:28:59.807 回答