我正在写一个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。这是db中的新字段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 deffinetly落在这两个日期之间,也不会返回任何数据。我不知道为什么会这样。我甚至试过这一行:
AND CR.GCR_RECEIVED_DT = '01-JAN-00'
我仍然没有得到返回的数据。它似乎只适用于LIKE。我已经检查过,该字段是日期类型。非常感谢任何帮助。
答案 0 :(得分: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')
... TO_DATE('31-DEC-99', 'DD-MON-YY')
是12月31日 2099 ,而非1999年。BETWEEN
仅在第一个值低于第二个值时起作用(来自the docs ,'如果expr3< expr2,则间隔为空')。因此,你正在寻找2099年和2000年的价值观,这将永远是空的。如果您的日期模型是DD-MON-RR
,来自NLS参数或明确地通过TO_DATE
,那么它将查找1999年到2000年之间的值,并找到您的记录。
您的第三个结果是更具推测性,但表明您的GCR_RECEIVED_DT
字段中的值具有时间组件,或者不在您认为的世纪中。这类似于LIKE
版本,除了这次将固定字符串转换为日期,而不是转换为字符串的日期;有效:
AND CR.GCR_RECEIVED_DT = TO_DATE('01-JAN-00', 'DD-MON-YY')
如果他们在2000-01-01
的午夜,这将有效。因为它并不表示它们要么是在午夜之后的某个时间,要么可能更有可能 - 因为你在现有记录中使用了'魔术'日期 - 它们完全是另一个日期,很可能是1900-01-01
。 / p>
以下是just past midnight和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
具有包容性,因此使用BETWEEN DATE '2000-01-01' AND '2000-01-02'
将包含您可能不想要的日期正好在午夜的任何记录。
无论你最终做什么,都要避免依赖使用NLS_DATE_FORMAT
的隐式转换,因为有一天它可能没有设置为你所期望的,导致潜在的数据损坏或很难找到错误;如果可以避免歧义,请在模型中指定完整的四位数年份。
答案 1 :(得分:1)
尝试这样的事情:
WHERE TRUNC(CR.GCR_RECEIVED_DT) = TO_DATE('01-JAN-00','DD-Mon-YY')
不带参数的TRUNC会从DATE中删除小时,分钟和秒。