How would you truncate or limit the results of a date result you are adding time to? (Oracle SQL) - sql

So I am doing a homework project where I have to display the current date, and then the date for three months from now, which I have done with this:
SELECT CURRENT_DATE AS "Today's Date", LOWER(ADD_MONTHS(CURRENT_DATE, 3)) AS "Today, Three Months Hence" FROM dual;
and again with this:
SELECT CURRENT_DATE AS "Today's Date", LOWER(CURRENT_DATE + INTERVAL '3' MONTH)AS "Today, Three Months Hence" FROM dual;
results:
Today's Date
05-FEB-14
Today, Three Months Hence
05-may-14
What I am wondering is if there is a way to display the results of the future date where it only shows the month and nothing else, (i.e. no day or year). Is this possible in Oracle, or am I just looking to try the impossible?

You just need to specify the display format, which you should really do anyway instead of relying on your session defaults:
SELECT TO_CHAR(CURRENT_DATE, 'DD/MM/YYYY') AS "Today's Date",
TO_CHAR(ADD_MONTHS(CURRENT_DATE, 3), 'YYYY-MM-DD')
AS "Today, Three Months Hence",
TO_CHAR(ADD_MONTHS(CURRENT_DATE, 3), 'Month') AS "Three Months Hence"
FROM dual;
| TODAY'S DATE | TODAY, THREE MONTHS HENCE | THREE MONTHS HENCE |
|--------------|---------------------------|--------------------|
| 06/02/2014 | 2014-05-06 | May |
Simple SQL Fiddle.
The available date format model elements are shown in the documentation.

A date value is actually stored as a number in database, not a character string. What you see in your result is the default date format interpretation of your session.
To change the way your date fields are displayed, you need to use to_char function.
select to_char(sysdate, 'MM') from dual;
'MM' parameter here stands for month, which is what you asked. It is a format string to convert a date into a character string. For a list of your options with format string, a simple google search will help you.

OK, I was looking at an example about to_char and finally sorted it out:
SELECT CURRENT_DATE AS "Today's Date", TO_CHAR(ADD_MONTHS(CURRENT_DATE, 3), 'month') AS "Today, Three Months Hence" FROM dual;
This is similar to the answer provided by Alex. I did notice that when I type in month in lower case the result is also in lower case, and when it type it in as MONTH, in upper case, the result is then in upper case, which is good to know. This wasn't required, but I was curious.

Related

Date_Trunc and To_Date Questions SQL

Can we use date_trunc for a date (not date-time) that we are trying to "truncate" (not sure if the term can be applied here) to e.g. the start of the week? So if I have date_trunc(week, 28/10/2020) and I want to get the start of the week that 28th of October lies in (so 26th of October)? I tried this in my SQL command line but I get error messages.
If I am doing: SELECT to_date ('02 Oct 2001', 'DD Mon YYYY'); How can I ensure the resulting format is in a date format I specify (rather than the default date format)? For example if I want it in format DD-MM-YYYY?
select to_char(date '2017-06-02', 'MM') < in this example, why do we need "date" for this to work? The general format for to_char should be TO_CHAR (timestamp_expression, 'format'). I don't see in this general format that we need "day".
if I have a WHERE filter like to_char(order_date, '20-10-2020'), and there are indeed some rows with this order date, will these rows still show in my results (after running query) if these rows are in DATE format (so 20 Oct is in date format) as opposed to string (which is what I am filtering by as I am doing to_char). I know there would be no need to use to_char in this case but just asking..
yes, you can use date in text form but you have to cast it to a correct type
these queries will work
select date_trunc('week', '2020-10-28'::date);
select date_trunc('week', '10/28/2020'::date);
-- as well as
select date_trunc('week', '2020-10-28'::datetime);
and return timestamp 2020-10-26 00:00:00.000000
note, next query
select date_trunc('week', '28/10/2020'::date);
will fail with error date/time field value out of range: "28/10/2020";
You can use to_char, it returns text, if you need a date format you have to case it again
select to_char( to_date ('02 Oct 2001', 'DD Mon YYYY'), 'DD-MM-YYYY')::date;
select to_char('02 Oct 2001'::date, 'DD-MM-YYYY')::date;
'2017-06-02' is a text and it can't be automatically converted to timestamp. Actually I don't know a text format which can.
No, you need to explicitly cast into date type to use it as a filter
where order_date = date_stored_as_a_text::date
I am answering the questions in a different order as there are some wrong assumptions:
Question 3
There is a general difference between '2017-06-02' and date '2017-06-02' - the first one is just a varchar, a string, NOT handled as a date by Redshift, the 2nd one tells Redshift to handle the string as date and therefore works.
Question 2
A date data type column has no format - you may an sql client that can display date columns in different formats, however, this is not a functionality of redshift. SELECT to_date ('02 Oct 2001', 'DD Mon YYYY'); tells redshift to convert the string '02 Oct 2001' to date.
Question 1
DATE_TRUNC('datepart', timestamp) also supports week as datepart - see Date parts for date or timestamp function (Also shown in the example of AWS). You should also be able to provide a date instead of a timestamp.
Question 4
to_char(order_date, '20-10-2020')is not a filter and you are using it wrong.
AWS TO_CHAR
TO_CHAR converts a timestamp or numeric expression to a character-string data format.
I guess you are rather looking for:
where to_char(order_date, 'YYYY-MM-DD') = '20-10-2020'

Maximo UI SQL Select Month

I am trying to write a query using SQL in the Maximo 7.5 UI advanced search function which will return data from the month before the month in which the query was run. I want to save this query and make it available to users who will run the query without editing it. For example, if a user ran the saved query on 1/25/2019, the query would return all records for which the date was any day in December 2018. I have previously used "where actfinish >= sysdate-30" but the length on months varies and I cannot rely on the users (who do not write SQL) to always run the query on the first day of each month, so I need the query to filter by the previous month. The field I am filtering on is a DATE field, but in the DB it looks like DD-MMM-YY.
Your current where actfinish >= sysdate-30 will return data from the current month, as well as the issues you mentioned.
You can do something like:
where actfinish >= add_months(trunc(sysdate, 'MM'), -1)
and actfinish < trunc(sysdate, 'MM')
The trunc(sysdate, 'MM') gives you midnight on the first day of the current month. The first clausesubtracts a month from that, so gives you midnight on the first day of the previous month; the second clause prevent any record from this month being included.
You can check what those evaluate to by querying the terms outside your real query:
alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS';
select sysdate,
add_months(trunc(sysdate, 'MM'), -1) as month_from,
trunc(sysdate, 'MM') as month_to
from dual;
SYSDATE MONTH_FROM MONTH_TO
------------------- ------------------- -------------------
2019-01-25 12:59:53 2018-12-01 00:00:00 2019-01-01 00:00:00
The alter session is just to make the client format the results in a particular way, instead of explicitly doing to_char().
When you said "in the DB it looks like DD-MMM-YY", it doesn't actually look like that in the database; when you query the date values your client is formatting the dates like that, so your NLS_DATE_FORMAT is probably set to the still-default DD-MON-RR model. (And it's MON in Oracle, not MMM - see the format model elements in the docs.)
Your solution will depend on the type of database that is being used.
For SQL Server, we have used logic along the following lines:
actfinish between dateadd(day,1,eomonth(dateadd(month,-2,getdate()))) and eomonth(dateadd(month,-1,getdate()))
(identify the last day of the previous month and the last day of the month before that + 1 day)
For Oracle, the equivalent would be:
trunc(actfinish,'MONTH') = add_months(trunc(sysdate,'MONTH'),-1)
(identify the year and month associated with last month and compare that against the target date components - trunc month function removes the time and day of month components so making comparisons easier)
I have previously used "where actfinish >= sysdate-30" but the length
on months varies.
By "length of month", do you mean the number of days for each month (e.g. 30, 31, 28, 29) or just a formatting issue with the month? If I understood your question correctly, you can convert the date to character then convert that to date and Oracle will take care of the change in the number of days. For example, something like:
where to_date(to_char(actfinish, 'mm/dd/yyyy')) >= to_date(to_char(sysdate, 'mm/dd/yyyy'))-30
or
where to_date(to_char(actfinish), 'mm/dd/yyyy') >= to_date(to_char(sysdate), 'mm/dd/yyyy')-30
I don't have Maximo installed on my personal laptop so you can try the two I listed above.

Oracle Julian day of year

how can I select Julian day of year in Oracle database?
I tried:
select to_char(sysdate, 'J') from dual;
Which gives me the number of days since January 1, 4712 BC. But I would need the number of days since 1.1. of current year.
If you check the TO_CHAR (datetime) documentation you get a link to "Format Models" with a comprehensive list of available formats. I guess you want this:
DDD Day of year (1-366)
SELECT TO_CHAR(SYSDATE, 'DDD') from DUAL;
One way would be to use:
select sysdate - trunc(sysdate,'yyyy') from dual
'Trunc' cuts everything except the year and returns 01/01/2014, subtracted by the sysdate returns numbers of days since 1st of january.
Use sql select trunc(sysdate)+1 - trunc(sysdate,'yyyy') from dual. you will get an even number

In MonetDB, how can I get the date as an integer?

I want to be able to do something like
SELECT cast(my_date_col AS int) FROM my_table;
I would like to get the integer which MonetDB uses internally, i.e. the value you'd find if you looked into the BAT structure and got the appropriate element in code in MonetDB's GDK. Now, AFAICT, this internal value is the number of days since the Epoch, being Jan 1st on "Year 0" (so January 3rdt year 2 would be 366+365+2 = 732).
The best I could actually manage is
SELECT my_date_col AS int - cast('1-1-1' AS date) - 366 FROM my_table;
As MonetDB won't accept "Year zero" dates. This is rather an ugly hack, I'd like to do better. Help me?
If you're trying to get the number of days between "my_date_col" and 1970-01-01, in standard SQL you'd just subtract the one from the other. Your platform, monetdb, seems to support this syntax, but I don't have it installed. I wrote these examples in PostgreSQL.
select current_date - date '1970-01-01' as num_days;
num_days
--
16213
Check that result by adding 16213 days to the current date (2014-05-23).
select cast ((date '1970-01-01' + interval '16213' day) as date) as target_date
target_date
--
2014-05-23
The cast is necessary, because the result of this addition is a timestamp, not a date.
In your case, you want a column name instead of "current_date". So you're looking for something along these lines.
select my_date_col - date '1970-01-01' as num_days
from your-table-name;

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:
...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. The Q is a valid date format symbol, so I'm not sure what's happened. 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. I would have expected 2009-08-04, since today is 2010-08-04.
This:
select to_date('2009 1','YYYY Q') from dual;
of course, fails.
(Oracle 10g)
Oracle says: 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.
See the second column of table 2.15 at 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
The crux of the issue is that you can not specify "Q" in the TO_DATE function.
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.
Since the relationship between quarters to months is one-to-many, it doesn't make sense to do 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.)
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. 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.)
I think the best way is to just input the quarter start date and quarter end dates without even bothering with 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
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
start_month= -2 + 3 * quarter
last_month = 3 * quarter
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