简体   繁体   English

具有四分之一格式的Oracle to_date函数

[英]Oracle to_date function with quarter-format

I need to find some records created in a range of quarters. 我需要查找在各个季度中创建的一些记录。 For example, I'm looking for all records created between the 4th quarter of 2008 and the 1st quarter of 2010. I have this in my WHERE-clause: 例如,我正在寻找在2008年第4季度到2010年第1季度之间创建的所有记录。在WHERE子句中有以下记录:

...and r.record_create_date between to_date('2008 4','YYYY Q')
                                and to_date('2010 1','YYYY Q')

but Oracle says: ORA-01820: format code cannot appear in date input format . 但是Oracle说: ORA-01820: format code cannot appear in date input format The Q is a valid date format symbol, so I'm not sure what's happened. Q是有效的日期格式符号,因此我不确定发生了什么。 Is this even a valid way to find values in between calender quarters, or is there a better way? 这是否是在日历季度之间查找值的有效方法,还是有更好的方法?


Also interesting, and possibly related, if I execute this: 如果执行此操作,也很有趣,并且可能相关:

select to_date('2009','YYYY') from dual;

The value displayed in my IDE is 2009-08-01 . 我的IDE中显示的值为2009-08-01 I would have expected 2009-08-04 , since today is 2010-08-04 . 我本来希望是2009-08-04 ,因为今天2010-08-04

This: 这个:

select to_date('2009 1','YYYY Q') from dual;

of course, fails. 当然会失败。

(Oracle 10g) (Oracle 10g)

Oracle says: ORA-01820: format code cannot appear in date input format . Oracle说: ORA-01820: format code cannot appear in date input format The Q is a valid date format symbol, so I'm not sure what's happened. Q是有效的日期格式符号,因此我不确定发生了什么。

See the second column of table 2.15 at http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34948 . 请参阅表2.15的第二列, 网址http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34948 Not all format elements are allowed when converting to dates, timestamps, etc. 转换为日期,时间戳等时,并非所有格式元素都被允许。

I recommend against using between for date range checks. 我建议不要在之间进行日期范围检查。 People often will miss values within the ending day that the expect to be included. 人们经常会在期望值包含的最后一天之内错过价值。 So I would translate: 所以我会翻译:

and r.record_create_date between to_date('2008 4','YYYY Q')
                             and to_date('2010 1','YYYY Q')

To

and to_date('2008-10-01', 'YYYY-MM-DD') <= r.record_create_date 
and record_create_date < to_date('2010-04-01', 'YYYY-MM-DD') -- < beginning of 2Q2010.

Someone asked the same question on OTN: http://forums.oracle.com/forums/thread.jspa?threadID=1081398&tstart=255 有人在OTN上问了同样的问题: http : //forums.oracle.com/forums/thread.jspa? threadID= 1081398& tstart= 255

The crux of the issue is that you can not specify "Q" in the TO_DATE function. 问题的症结在于您不能在TO_DATE函数中指定“ Q”。

Given that you're already specifying a portion of the date, why not provide the entire date? 既然您已经指定了日期的一部分,为什么不提供整个日期呢? Mind too that to_date('2010 1','YYYY Q') would give you Jan 1st, 2010 when you really want March 31st, 2010... at a second to midnight. to_date('2010 1','YYYY Q')记住, to_date('2010 1','YYYY Q')会给您2010年1月1日,而您真正想要的是2010年3月31日……仅次于午夜。

Since the relationship between quarters to months is one-to-many, it doesn't make sense to do TO_DATE('2008 1', 'yyyy q'); 由于季度与月份之间的关系是一对多的,因此执行TO_DATE('2008 1','yyyy q')没有意义。 what date should be returned? 应该返回什么日期? The first of the quarter, the end of the quarter, ...? 第一季度的第一季度末,...? (On the other hand, converting a date to a quarter - like TO_CHAR(SYSDATE, 'yyyy q') makes sense because a specific date only exists in one quarter.) (另一方面,将日期转换为四分之一-如TO_CHAR(SYSDATE,'yyyy q')是有意义的,因为特定日期仅存在于四分之一中。)

So, if you do want a query that looks for a date that falls between two quarters, you will have to "rolll your own" (explicitly stating the dates of the start/end of a quarter.) 因此,如果您确实希望查询的日期介于两个季度之间,则必须“滚动自己的日期”(明确说明一个季度开始/结束的日期。)

As a side note, in case anyone is considering not using TO_DATE please do not use things like: WHERE date_value BETWEEN 'date string1' and 'date string2' without the TO_DATE function. 附带说明一下,如果有人考虑不使用TO_DATE,请不要使用类似这样的东西:WHERE date_value BETWEEN'date string1'和'date string2',而没有TO_DATE函数。 It assumes a default date format and under certain situations can avoid potentially useful indexes altogether. 它采用默认的日期格式,并且在某些情况下可以完全避免潜在有用的索引。

Below is one example where the same query can have a different result. 下面是一个示例,其中同一查询可能会有不同的结果。

select sysdate from dual where sysdate between '1-Jan-10' and '31-Dec-10';


SYSDATE
---------
04-AUG-10

SQL> alter session set nls_date_format = 'YYYY-MM-DD';

Session altered.

SQL> select * from dual where sysdate between '1-Jan-10' and '31-Dec-10'; 

no rows selected

(Notice that in the second instance no error is returned. It just assumes Jan 10, 0001 and Dec. 10th, 0031.) (请注意,在第二种情况下,不会返回任何错误。它仅假设0001年1月10日和0031年12月10日。)

I think the best way is to just input the quarter start date and quarter end dates without even bothering with to_date. 我认为最好的方法是只输入季度开始日期和季度结束日期,而不必担心to_date。 I think if you use 我想如果你用

between '1-Jan-10' and '31-Dec-10'

for example, then you don't (in Oracle I believe) need to_date and it isn't much more difficult than typing in the quarter number 例如,那么您就不需要(在Oracle中,我相信)需要to_date,并且它比输入四分之一号要困难得多

To calculate in Oracle the first day of a quarter and the last day of a quarter from the year and quarter: I Use the fact 要在Oracle中从年份和季度计算季度的第一天的第一天和季度的最后一天:

start_month= -2 + 3 * quarter start_month = -2 + 3 *季度

last_month = 3 * quarter last_month = 3 *季度

variable v_year    number

variable v_quarter number

exec :v_year     :=2017

exec :v_quarter:=4

select :v_year    as year,
       :v_quarter as quarter,
       to_date(:v_year||to_char(-2+3*:v_quarter,'fm00'),'yyyymm')        as quarter_start,
       last_day(to_date(:v_year||to_char(3*:v_quarter,'fm00')||'01 23:59:59','yyyymmdd hh24:mi:ss')) as quarter_end
from dual a;


YEAR|QUARTER|QUARTER_START      |QUARTER_END        
2017|      4|2017-10-01 00:00:00|2017-12-31 23:59:59

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM