我在处理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;
答案 0 :(得分:3)
现在,您需要正确转换日期。
TO_DATE(hist.DATESTAMP,' MM / YYYY')
以上是错误的,因为您的日期存储为'dd/mm/yyy'
,因此使用格式掩码4/23/2015
将mm/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'
如果该列确实是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子句执行日期过滤器,这在以前引起了问题。
感谢您的所有帮助和支持。我想我最终会走上正确的道路。