Oracle SQL Developer中的未知SQL编码问题

时间:2013-08-28 15:18:21

标签: sql oracle-sqldeveloper

我正在写一个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。我已经检查过,该字段是日期类型。非常感谢任何帮助。

2 个答案:

答案 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 midnight1900的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中删除小时,分钟和秒。