转换Oracle日期

时间:2016-05-30 21:05:20

标签: oracle date

我在处理Oracle中的日期时遇到了最困难的时期。由于日期问题,我发现自己花了几个小时试图编译和运行查询。我不明白这是多么有用。

我有一个文本字段4/23/2015作为日期。我需要将这个日期转换成两种形式; 2015年4月和2015年4月23日。我已经想出如何通过使用TO_CHAR和TO_DATE转换为这两种类型,但我的结果似乎不一致。

当我尝试转换为MM / YYYY格式时,我遇到此失败:ORA-01841 :(完整)年份必须介于-4713和+9999之间,而不是0

TO_DATE(hist.DATESTAMP, 'MM/YYYY')

如果我将其更改为TO_CHAR(hist.DATESTAMP, 'MM/YYYY')它按预期工作,但现在在给定日期之后显示项目的查询不再有效,因为它现在是字符串而不是日期。 WHERE DATESTAMP > '04/01/2015'

我有一个大型csv文件,我将数据导入Oracle表,需要提供报告。

我需要在日期搜索结果,并且报告只显示月份和年份。通过分组合并的总数将在月内显示总数。

在SQL Server中,我可以轻松完成此任务。但是,在处理日期时,Oracle是一个巨大的痛苦,我不知道如何正确地工作。

我一直在阅读我能在日期找到的每一个来源,特别是在这里。在一个选择通过双重的真空中,我可以将字符串转换为日期,并将该日期转换为我的月/年字符串。但是我的活动导入表在日期错误后继续抛出错误。

我可以使用一些真正的指导。谢谢

好奇的表格和脚本

CREATE TABLE MONTHLY_DATA
(
  ID                     NUMBER(10)             NOT NULL,
  DATESTAMP              DATE                   NOT NULL,
  PARTNER                VARCHAR2(256 BYTE)     NOT NULL,
  APPNAME                VARCHAR2(256 BYTE)     NOT NULL,
  TYPE_NAME              VARCHAR2(256 BYTE)     NOT NULL,
  PLATFORM               VARCHAR2(10 BYTE)      NOT NULL, -- RED or BLUE
  VOLUME                 NUMBER(10)             NOT NULL,
  LBSSUMMARY             VARCHAR2(5 BYTE)       NOT NULL, -- TRUE or FALSE
  CREATE_DTS             DATE,
  MODIFIED_DTS           DATE,
  LAST_MODIFIED_USER     VARCHAR2(40 BYTE)
)


CREATE TABLE MONTHLY_SUMMARY
(
  DATESTAMP           DATE                      NOT NULL,
  RED_VOLUME          NUMBER(10)                NOT NULL,
  BLUE_VOLUME         NUMBER(10)                NOT NULL,
  LBS_VOLUME          NUMBER(10)                NOT NULL,
  CREATE_DTS          DATE,
  MODIFIED_DTS        DATE,
  LAST_MODIFIED_USER  VARCHAR2(40 BYTE)
)

MONTHLY_DATA中的数据每月约有5万行。 目标是总结这些数据,并提供整体量。

此外,NLS设置为:     select * from nls_session_parameters where parameter ='NLS_DATE_FORMAT'; NLS_DATE_FORMAT:DD-MON-RR

为该月分组的MONTHLY_SUMMARY的值。每个月应该只有一排;

  

03/2015 52 77 19

     

04/2015 34 76 21

这两个表都用于使用日期构建报告。使where子句简单;如上所述是什么 我是在追求。在哪里DATESTAMP> '04 / 01/2015',但似乎我需要使用TO_DATE进行转换。

这是加载数据的脚本。

   INSERT INTO MONTHLY_SUMMARY (DATESTAMP, RED_VOLUME, BLUE_VOLUME, LBS_VOLUME)
   SELECT DISTINCT
          MONTHLY_DATA.DATESTAMP,
          CASE WHEN red.VOLUME IS NULL THEN 0 ELSE red.VOLUME END AS RED_VOLUME,
          CASE WHEN blue.VOLUME IS NULL THEN 0 ELSE blue.VOLUME END AS BLUE_VOLUME,
          CASE WHEN lbs.VOLUME IS NULL THEN 0 ELSE lbs.VOLUME END AS LBS_VOLUME
   FROM MONTHLY_DATA hist
   LEFT JOIN (SELECT DATESTAMP, SUM(hist.VOLUME) AS VOLUME
              FROM MONTHLY_DATA md
              WHERE PLATFORM = 'RED'
              GROUP BY DATESTAMP) red
          ON md.DATESTAMP = red.DATESTAMP
   LEFT JOIN (SELECT DATESTAMP, SUM(hist.VOLUME) AS VOLUME
              FROM MONTHLY_DATA md
              WHERE PLATFORM = 'BLUE'
              GROUP BY DATESTAMP) blue
          ON md.DATESTAMP = blue.DATESTAMP
   LEFT JOIN (SELECT DATESTAMP, SUM(MONTHLY_DATA.VOLUME) AS VOLUME
              FROM MONTHLY_DATA
              WHERE LBSSUMMARY = 'TRUE' 
              GROUP BY DATESTAMP) lbs
          ON MONTHLY_DATA.DATESTAMP = lbs.DATESTAMP
   WHERE MONTHLY_DATA.DATESTAMP 
     NOT IN (SELECT DISTINCT DATESTAMP FROM MONTHLY_SUMMARY)
   GROUP BY 
         MONTHLY_DATA.DATESTAMP,
         red.VOLUME,
         blue.VOLUME,
         lbs.VOLUME
   ORDER BY 1;

2 个答案:

答案 0 :(得分:3)

将字符串/ varchar值转换为日期

现在,您需要正确转换日期。

  

TO_DATE(hist.DATESTAMP,' MM / YYYY')

以上是错误的,因为您的日期存储为'dd/mm/yyy',因此使用格式掩码4/23/2015mm/yyyy之类的varchar值转换为正确的日期将无效。您需要提供与输入匹配的格式掩码。您 使用TO_DATE(hist.DATESTAMP, 'dd/MM/YYYY')

  

如果我将其更改为TO_CHAR(hist.DATESTAMP,' MM / YYYY'),则按预期工作

这不是"按预期工作",因为to_char()DATE值转换为字符串/ varchar值。但是您将varchar值传递给函数,该函数首先将隐式转换为日期以使函数调用工作。此转换取决于运行该语句的客户端的区域设置(NLS)设置。在我的计算机上,您的查询将失败,因为我的默认日期格式不同。

如果您想以不同的格式显示字符串,首先必须将其正确转换为日期,然后将该日期转换回字符串:

to_char(TO_DATE(hist.DATESTAMP, 'dd/MM/YYYY'), 'mm/yyyy')

如果您将日期正确存储为DATE to_char((hist.DATESTAMP,' mm / yyyy')就足够了。

如果您想使用"日期"条件值 首先将字符串值转换为正确的日期:

WHERE to_date(DATESTAMP, 'mm/dd/yyyy') > to_date('04/01/2015', 'dd/mm/yyyy')

现在将日期与日期进行比较。 WHERE DATESTAMP > '04/01/2015'正在将字符串与字符串进行比较。由于格式为mm/dd/yyyy,因此无法正常工作。如果你真的想存储和比较字符串,你至少应该以可以正确比较的格式存储它们,例如yyyy-mm-dd

对于日期常量,我更喜欢使用简短且不明显的ANSI日期文字:

WHERE to_date(DATESTAMP, 'mm/dd/yyyy') > DATE '2015-04-01'

比较Oracle

中的日期值

如果该列确实是date(正如您的评论现在所示),那么您需要做的就是:

WHERE DATESTAMP > DATE '2015-04-01'

或者如果您只是想检查特定的月份和年份组合:

where extract(year from datestamp) = 2015
  and extract(month from datestamp) = 4

where (extract(year from datestamp), extract(month from datestamp)) = ((2015,4))

或者这确实可以使用字符串比较来完成:

where to_char(datestamp, 'yyyy-mm') = '2015-04'

或者,如果您更喜欢可以使用datestamp

上的索引的查询
where datestamp >= date '2015-04-01'  
  and datestamp < date '2015-05-01'  

关于Oracle中日期的唯一真正烦人的事情是它们总是包含时间部分。在我看来,Oracle没有兴趣解决这个问题。通过引入新的DATE2类型或类似的东西。

答案 1 :(得分:0)

经过大量的车轮旋转和尝试一切,我相信我找到了误解的关键。 TO_DATE和TO_CHAR方法需要NLS格式作为日期。如果您尝试使用其他格式,则可能会出现错误的风险。

将初始格式转换为DD-MON-RR后,所有部分都开始正常工作。我还能够使用where子句执行日期过滤器,这在以前引起了问题。

感谢您的所有帮助和支持。我想我最终会走上正确的道路。