Date difference not matching - sql

I have the below query which gives the below output. The '06/01/20' is some corrupted data I need to deal with. Converting it to 'DD/MM/YY' is not an option, I just would like to understand what's happening here.
WITH aux (
d1,
d2
) AS (
SELECT
'06/01/20',
'15/01/2021'
FROM
dual
)
SELECT
nvl(to_date(d2, 'DD/MM/YYYY'), sysdate) - to_date(d1, 'DD/MM/YYYY') diff
FROM
aux;
Output:
DIFF
----
730862
However, if I do the below, the results do not match with what I would expect, the difference between those dates would be
SELECT
TO_DATE('06/01/20', 'DD/MM/YYYY') d1,
TO_DATE('15/01/2021', 'DD/MM/YYYY') d2
FROM
dual
Output:
D1 D2
---------------------
06-JAN-20 15-JAN-21
--
SELECT
DATE '2021-01-15' - DATE '2020-01-06' d
FROM
dual
Output:
D
-
9

I suggest you set a default date format that allows to see full dates. Many Oracle clients have such settings and you can also change it for current session:
ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD';
When you do so you'll realise that TO_DATE('06/01/20', 'DD/MM/YYYY') produces 0020-01-06 rather than 2020-01-06.
An average year has 365.25 days and 730862 / 365,25 equals 2001 ;-)

Related

BETWEEN Two Dates is Returning Rows of the Same Two Dates instead of the Ones Between

I'm trying to select rows that are between two specific dates, but I'm getting the rows that are of the same dates specified in BETWEEN instead. I tried using operators > and <, but nothing seems to work. Does it have to do with the date format?
SELECT r.RESERVATION_ID, a.AGENT_ID, a.AGENT_FNAME AS AGENT_NAME, t.TRIP_ID,
s.RESERVATION_STATUS
FROM RESERVATION r
INNER JOIN AGENT a
ON
a.AGENT_ID=r.AGENT_ID
INNER JOIN TOURTRIP_RESERVATION t
ON
r.RESERVATION_ID=t.RESERVATION_ID
INNER JOIN RESERVATION_STATUS s
ON
r.RESERVATION_STATUSID=s.RESERVATION_STATUSID
WHERE r.AGENT_ID IS NOT NULL
AND r.RESERVATION_DATE BETWEEN '15-MAR-20' AND '26-MAY-20'
AND r.RESERVATION_STATUSID=100;
I used to_date('03.06.2020','DD.MM.YYYY') format to update the data in the reservation_id column. However, when I use
and RESERVATION_DATE > to_date('15.03.2020','DD.MM.YYYY')
and RESERVATION_DATE < to_date('26.05.2020','DD.MM.YYYY')
it's returning nothing
This is the reservation table
The condition between includes the start and the end.
You can use the operators > and < to exclude it.
Your example simplified:
create table RESERVATION (
RESERVATION_ID number
,RESERVATION_DATE date)
Data:
insert into RESERVATION values (1, to_date('01.06.2020','DD.MM.YYYY'));
insert into RESERVATION values (2, to_date('02.06.2020','DD.MM.YYYY'));
insert into RESERVATION values (3, to_date('03.06.2020','DD.MM.YYYY'));
Query A)
select RESERVATION_ID
from RESERVATION
where RESERVATION_DATE between to_date('01.06.2020','DD.MM.YYYY')
and to_date('03.06.2020','DD.MM.YYYY')
will return:
1
2
3
The Query B)
select RESERVATION_ID
from RESERVATION
where RESERVATION_DATE > to_date('01.06.2020','DD.MM.YYYY')
and RESERVATION_DATE < to_date('03.06.2020','DD.MM.YYYY')
will return
2
I assume that RESERVATION_DATE is a date. Use always explicit datatype conversion.
I changed the date format, try this and tell me if you have other result.
SELECT r.RESERVATION_ID, a.AGENT_ID, a.AGENT_FNAME AS AGENT_NAME, t.TRIP_ID,
s.RESERVATION_STATUS
FROM RESERVATION r
INNER JOIN AGENT a
ON
a.AGENT_ID=r.AGENT_ID
INNER JOIN TOURTRIP_RESERVATION t
ON
r.RESERVATION_ID=t.RESERVATION_ID
INNER JOIN RESERVATION_STATUS s
ON
r.RESERVATION_STATUSID=s.RESERVATION_STATUSID
WHERE r.AGENT_ID IS NOT NULL
AND r.RESERVATION_DATE BETWEEN '2020-03-15' AND '2020-05-26'
AND r.RESERVATION_STATUSID=100;
If RESERVATION_DATE column's datatype is DATE, don't compare it to strings, because '15-MAR-20' is a string. Oracle will try to implicitly convert it to a valid date value; sometimes it'll succeed, sometimes it'll return false value (as its NLS settings differ from what you provided), and sometimes it'll fail and raise an error.
These two:
date '2020-03-15'
to_date('15.03.2020', 'dd.mm.yyyy')
on the other hand, are dates.
BETWEEN is inclusive and will return both limits, if they exist:
AND r.RESERVATION_DATE BETWEEN date '2020-03-15' and date '2020-05-26'
If you want to exclude those limits, then
AND r.RESERVATION_DATE > date '2020-03-15'
AND r.RESERVATION_DATE < date '2020-05-26'
But, if RESERVATION_DATE is a VARCHAR2 column, you're doing a big mistake. Never store dates as strings. If you can't afford modifying datatype, then you'll have to convert it to date:
and to_date(r.reservation_date, 'dd-mon-yy') between date '2020-03-15'
and date '2020-05-26'
This will work as long as there aren't any invalid values in that column. Because, as it is a string, you can put something like 15-AA-2F which certainly isn't a date, but can be stored into such a column. In that case, query will fail and you'll have to fix data.
Comment you posted says that you tried TO_DATE('26-MAY-20'). That's not enough - you should provide format mask as that can be
26th of May 2020
20th of May 2026
and it depends on NLS settings. Furthermore, it'll fail in my database:
Because NLS settings are different:
SQL> select to_date('26-may-20') from dual;
select to_date('26-may-20') from dual
*
ERROR at line 1:
ORA-01858: a non-numeric character was found where a numeric was expected
Because we don't have "may" in Croatia:
SQL> select to_date('26-may-20', 'dd-mon-yy') from dual;
select to_date('26-may-20', 'dd-mon-yy') from dual
*
ERROR at line 1:
ORA-01843: not a valid month
But this works, as I told Oracle what I want:
SQL> select to_date('26-may-20', 'dd-mon-yy', 'nls_date_language = english') from dual;
TO_DATE('26-MAY-20'
-------------------
26.05.2020 00:00:00
Even better, use digits only or date literal (which is always a date 'yyyy-mm-dd'):
SQL> select to_date('26.05.2020', 'dd.mm.yyyy') d1,
2 date '2020-05-26' d2
3 from dual;
D1 D2
------------------- -------------------
26.05.2020 00:00:00 26.05.2020 00:00:00
SQL>
Based on sample data you provided, presuming that reservation_date column's datatype is date:
setting environment first
sample data is from line #1 - 9
query you need begins at line #10
Here you go:
SQL> alter session set nls_date_language = 'english';
Session altered.
SQL> alter session set nls_Date_format = 'dd-mon-yy';
Session altered.
SQL> with reservation (reservation_id, reservation_date, agent_id) as
2 (select 8576, date '2020-03-15', 222 from dual union all
3 select 7325, date '2020-05-26', 333 from dual union all
4 select 3186, date '2020-04-23', 111 from dual union all
5 select 8000, date '2020-04-05', 555 from dual union all
6 select 4120, date '2020-01-03', null from dual union all
7 select 1546, date '2020-02-15', null from dual union all
8 select 1007, date '2020-05-06', null from dual
9 )
10 select *
11 from reservation
12 where reservation_date between date '2020-03-15'
13 and date '2020-05-26'
14 order by reservation_date;
RESERVATION_ID RESERVATI AGENT_ID
-------------- --------- ----------
8576 15-mar-20 222
8000 05-apr-20 555
3186 23-apr-20 111
1007 06-may-20
7325 26-may-20 333
SQL>

Doing Math with Dates given in the problem

The following is the query and code attached to the query.I am not able to figure out how to use the date 31-dec-2006 in the problem.
For each rental property, list the address, include street, city, state.
Also list rental type and number of days listed as "Number of Days Listed". Order results by rental type ascending and number of days listed descending.
Instead of using today's date to determine days listed, use 31-dec-2006
The issue is that Im not receiving any results for this query. I believe I am doing something wrong in the where statement. Im not sure how to assigne a value to the date.
select rp_street, rp_city, rp_state, rp_type, (rp_datelisted - sysdate) as "Number of Days Listed"
from rentproperty
where sysdate = '31-dec-2006'
order by rp_type asc, "Number of Days Listed" desc;
When working with dates, then work with dates, not strings. '31-dec-2006' is just a string. It looks like a date (to us, humans), Oracle will try to convert it to a date (if it can), but you can never be sure it'll work. For example, it won't work in my database:
SQL> select count(*) From emp where hiredate < '31-dec-2006';
select count(*) From emp where hiredate < '31-dec-2006'
*
ERROR at line 1:
ORA-01858: a non-numeric character was found where a numeric was expected
If I fix several things, it will work:
SQL> alter session set nls_date_language = english;
Session altered.
SQL> alter session set nls_date_format = 'dd-mon-yyyy';
Session altered.
SQL> select count(*) From emp where hiredate < '31-dec-2006';
COUNT(*)
----------
14
SQL>
Therefore, either use a date literal (which always looks like date 'yyyy-mm-dd'), or apply the TO_DATE function to a string, with appropriate format mask, e.g. to_date('31.12.2006', 'dd.mm.yyyy') and your query will always work.
Here's what you could have done (I shortened the column list); the RENTPROPERTY CTE lists some sample data; you need code from line 7 onwards.
SQL> with rentproperty (rp_street, rp_type, rp_datelisted) as
2 (select 'Oak street' , 'Type A', date '2000-01-25' from dual union all
3 select '31st street', 'Type B', date '2001-10-30' from dual union all
4 select 'Elm street' , 'Type B', date '2004-08-25' from dual union all
5 select 'Bee street' , 'Type A', date '2006-11-30' from dual
6 )
7 select rp_street,
8 rp_type,
9 (date '2006-12-31' - rp_datelisted) days_listed
10 from rentproperty
11 where rp_datelisted < date '2006-12-31'
12 order by rp_type asc, days_listed desc;
RP_STREET RP_TYP DAYS_LISTED
----------- ------ -----------
Oak street Type A 2532
Bee street Type A 31
31st street Type B 1888
Elm street Type B 858
SQL>
In oracle, sysdate is the current date, so unless today is 31-dec-2006, you'll never get any results. If you've used "sysdate" as the column name, try putting it in quotes.
sysdate = '31-dec-2006' condtion is false that is why no output!!
this is probably what you need:
select rp_street, rp_city, rp_state, rp_type, (rp_datelisted - sysdate) as "Number of
Days Listed"
from rentproperty
where rp_datelisted= '31-dec-2006'
order by rp_type asc, "Number of Days Listed" desc;
The Oracle sysdate returns date and time. Try trunc(sysdate) to compare similar values.
select rp_street, rp_city, rp_state, rp_type, (rp_datelisted - sysdate) as "Number of Days Listed"
from rentproperty
where trunc(sysdate) = '31-dec-2006'
order by rp_type asc, "Number of Days Listed" desc;

Oracle order by date gives different results

Just curious as to why the below two queries would give different results, when the testdate column is of datatype DATE.
select testdate from <table> order by to_date(testdate) desc;
Returns
18-DEC-14
17-DEC-14
14-JUL-14
10-JUL-14
.
select testdate from <table> order by testdate desc;
Returns
13-NOV-13
18-DEC-14
17-DEC-14
14-JUL-14
Why would that November 2013 result appear at the top of the second results when as I say the coumn TESTDATE is of data tyle DATE and to_date() resolves the issueX?
Based on OP's reply via comments, the issue is:
SQL> WITH dates(dt) AS(
2 SELECT to_date('18-DEC-2014', 'DD-MON-RR') FROM dual UNION ALL
3 SELECT to_date('17-DEC-2014', 'DD-MON-RR') FROM dual UNION ALL
4 SELECT to_date('14-JUL-2014', 'DD-MON-RR') FROM dual UNION ALL
5 SELECT to_date('10-JUL-2014', 'DD-MON-RR') FROM dual UNION ALL
6 SELECT to_date('13-NOV-3013', 'DD-MON-RR') FROM dual
7 )
8 SELECT dt yy_date,
9 TO_CHAR(dt, 'DD-MON-YYYY') yyyy_date
10 FROM dates
11 ORDER BY dt DESC;
YY_DATE YYYY_DATE
--------- -----------
13-NOV-13 13-NOV-3013
18-DEC-14 18-DEC-2014
17-DEC-14 17-DEC-2014
14-JUL-14 14-JUL-2014
10-JUL-14 10-JUL-2014
SQL>
Th client is displaying the year as YY due to which year 3013 is displayed as 13 and along with other dates 2014, it looked as if 2013 is ordered before 2014 in descending order.
Use TO_CHAR to display the date in your desired format, and use TO_DATE to convert a literal into date.
On a side note,
Never use TO_DATE on a DATE, It will implicitly convert it into string and then back to date using locale-specific NLS format.
TO_DATE function expects string to convert it to date with a given format. Providing date column to to_date may result in unexpected behaviour even oracle does not complain about the given input.

Table left join with itself returning NULL

I have a table like
Tdate Symbol new_close
20100110 xxx 1.2
20100111 xxx 1.3
...
20100110 yyy 1.1
20100111 yyy 1.5
Where Tdate was stored as integer and updated per day for each symbol. I want generate a new table from it by subtracting new_close value to its previous one, which looks like this
Tdate Symbol delta
20100110 xxx =1.2-1.2
20100111 xxx =1.3-1.2
...
20100110 yyy =1.1-1.1
20100111 yyy =1.5-1.1
Here is my code
with delta as
( select a.Tdate as TDate, a.Symbol as Symbol,
a.new_close-b.new_close as Pdelta, b.new_close as oldPrice
from ctsWithSplit a left join ctsWithSplit b
on a.TDate-b.TDate=1 and a.Symbol=b.Symbol)
However, in the new generated table, some delta value is NULL, how to fix it please?
Why is TDATE being stored as a number? Your query will fail to find the previous day when the date is the first of the month - eg: 20150201 - 20150131 = 70, whereas there's only a day between 31st Jan and 1st Feb.
Store dates as DATE or TIMESTAMP datatype, and then you give Oracle a chance at getting the date arithmetic correct.
Perhaps you're after something like:
with sample_data as (select to_date('10/01/2010', 'dd/mm/yyyy hh24:mi:ss') tdate, 'xxx' symbol, 1.2 new_close from dual union all
select to_date('11/01/2010', 'dd/mm/yyyy hh24:mi:ss') tdate, 'xxx' symbol, 1.3 new_close from dual union all
select to_date('10/01/2010', 'dd/mm/yyyy hh24:mi:ss') tdate, 'yyy' symbol, 1.1 new_close from dual union all
select to_date('11/01/2010', 'dd/mm/yyyy hh24:mi:ss') tdate, 'yyy' symbol, 1.5 new_close from dual)
select tdate,
symbol,
new_close - lag(new_close, 1, new_close) over (partition by symbol order by tdate) delta
from sample_data;
TDATE SYMBOL DELTA
---------- ------ -----
10/01/2010 xxx 0.0
11/01/2010 xxx 0.1
10/01/2010 yyy 0.0
11/01/2010 yyy 0.4
If you've never worked with analytic functions, then I suggest you look them up - they're incredibly useful and very powerful.
N.B. If you can't convert your TDATE column to be DATE datatype, then you need to convert the column into a date in any queries you run by using to_date().
When your left join doesn't find a matching row in b (i.e. on the first Tdate, or where there isn't a Tdate for the preceding day), then b.new_close will be NULL, as will the result of the subtraction.
Try:
select
a.Tdate as TDate,
a.Symbol as Symbol,
CASE WHEN b.new_close IS NULL THEN 0 ELSE a.new_close-b.new_close END as Pdelta,
b.new_close as oldPrice
from ctsWithSplit a
left join ctsWithSplit b
on a.TDate-b.TDate=1
and a.Symbol=b.Symbol

Converting YYWW to date in Oracle

I'm having some trouble with converting week number to date in oracle 11g.
The thing is that i have two columns *id|week_code* and I'd like to convert it to first day (monday) of this week.
So let's say that i have 1202 which is 2nd week of 2012, so the result would be like: 09-January-2012.
Thanks in advance.
Try to use this approach: (not tested).
with date_wk as (
select to_date('01/01/'||'20'||substr(%input%,1,2), 'MM/DD/
RRRR') + rownum - 4 dt
from dual
connect by level <= 366
),
wk_dt as (
select dt, to_number(to_char(dt, 'iw')) wk_of_yr
from date_wk
)
select min(dt)
from wk_dt
where wk_of_yr = substr(%input%,3,2)
to get the date you desire, and change it format to 'DD-MONTH-YYYY'.