[user#hostname ~]$ sqlplus -v
SQL*Plus: Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
select
a.user_id as user_id,
/* convert to minutes */
(to_date(a.modified_datetime, 'yyyy/mm/dd hh24:mi:ss') - to_date(b.modified_datetime, 'yyyy/mm/dd hh24:mi:ss')) 60 * 24 as minutes
from
(select user_id, modified_datetime, from table_name where some_conditions) a,
(select user_id, modified_datetime, from table_name where other_conditions) b,
where a.user_id = b.user_id
;
If a.modified_datetime is '2021/10/01 13:00:00' and b.modified_datetime is '2021/10/01 12:30:00', the result of this query would be:
user_id minutes
------- -------
12345 30
However, I run this query via sqlplus, it returns
user_id minutes
------- -------
12345 0
What's wrong with this query, or need to set some options to sqlplus?
it is stored in a date column
As #a_horse_with_no_name pointed out in a comment, calling to_date() on a value that is already a date is incorrect, and is causing your apparent problem.
When you do:
to_date(a.modified_datetime, 'yyyy/mm/dd hh24:mi:ss')
you are implicitly converting the date to a string using the current session NLS settings; with the still-default DD-MON-RR for example, that is really doing:
to_date(a.modified_datetime, 'yyyy/mm/dd hh24:mi:ss')
-> to_date(to_char(a.modified_datetime), 'yyyy/mm/dd hh24:mi:ss')
-> to_date(to_char(a.modified_datetime, <NLS_DATE_FORMAT>), 'yyyy/mm/dd hh24:mi:ss')
-> to_date(to_char(a.modified_datetime, 'DD-MON-RR'), 'yyyy/mm/dd hh24:mi:ss')
-> to_date('01-OCT-21', 'yyyy/mm/dd hh24:mi:ss')
-> 0001-10-21 00:00:00
As both values end up as midnight, the difference between them is calculated as zero minutes.
You could change the NLS settings, which is fragile; or explicitly convert the the date to a string in the right format - but neither is necessary or useful.
You should not have the to_date() calls at all, and can just subtract the date values directly from each other:
select
a.user_id as user_id,
(a.modified_datetime - b.modified_datetime) * 60 * 24 as minutes
from
(select user_id, modified_datetime from table_name where some_conditions) a,
(select user_id, modified_datetime from table_name where other_conditions) b
where a.user_id = b.user_id;
or using ANSI joins:
select
a.user_id as user_id,
(a.modified_datetime - b.modified_datetime) * 60 * 24 as minutes
from
(select user_id, modified_datetime from table_name where some_conditions) a
join
(select user_id, modified_datetime from table_name where other_conditions) b
on a.user_id = b.user_id;
db<>fiddle showing the results of the implicit conversions, and the correct output.
It is 30 minutes, if values really are as you stated:
SQL> with test (a_time, b_time) as
2 (select to_date('2021/10/01 13:00:00', 'yyyy/mm/dd hh24:mi:ss'),
3 to_date('2021/10/01 12:30:00', 'yyyy/mm/dd hh24:mi:ss')
4 from dual
5 )
6 select (a_time - b_time) * 60 * 24 as minutes
7 from test;
MINUTES
----------
30
SQL>
Related
I am trying to add minutes to my sql but no error and no data.
This is my sql
select distinct mo.reference_no payment_id, mo.dcn message_id,
mo.amount, mo.ccy, decode (mo.msg_status, 'R', 'Repair', 'P',
'Processed','N','Ungenerated','G','Generated',mo.msg_status)
message_status, to_char
(MO.INSERT_TIME,'DD-MM-YYYY HH24:MI:SS')
paym_date, mo.branch_date, mo.maker_id
from table1 mo
left join table2 mi
on mo.reference_no = mi.generated_ref_no
where mo.swift_msg_type = 103
and mo.ccy = 'XXX' and mo.branch_date = trunc(sysdate)
and mo.msg_status in('R','N','G','P')
order by PAYM_DATE desc;
And I want to add 5 minutes to (MO.INSERT_TIME,'DD-MM-YYYY HH24:MI:SS')
So I want my sql show me after 5 minutes for this column (MO.INSERT_TIME,'DD-MM-YYYY HH24:MI:SS')
I wrote sql like that
select distinct mo.reference_no payment_id, mo.dcn message_id,
mo.amount, mo.ccy, decode (mo.msg_status, 'R', 'Repair', 'P',
'Processed','N','Ungenerated','G','Generated',mo.msg_status)
message_status, to_char
(MO.INSERT_TIME,'DD-MM-YYYY HH24:MI:SS')
paym_date, mo.branch_date, mo.maker_id
from table1 mo
left join table2 mi
on mo.reference_no = mi.generated_ref_no
where mo.swift_msg_type = 103
and mo.ccy = 'XXX' and mo.branch_date = trunc(sysdate)
and MO.INSERT_TIME = to_date (sysdate,'DD-MM-YYYY HH24:MI:SS') + INTERVAL '5' MINUTE
and mo.msg_status in('R','N','G','P')
order by PAYM_DATE desc;
And after 5 minutes I am selecting this sql and their is no data. Can you explain why?
This is what you used:
and MO.INSERT_TIME = to_date (sysdate,'DD-MM-YYYY HH24:MI:SS') + INTERVAL '5' MINUTE
It is wrong because you're applying TO_DATE function to SYSDATE which already returns DATE datatype, so there's no point in doing it.
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> select sysdate,
2 sysdate + interval '5' minute
3 from dual;
SYSDATE SYSDATE+INTERVAL'5'
------------------- -------------------
10.01.2023 09:49:05 10.01.2023 09:54:05
SQL>
It is probably not very likely that MO.INSERT_TIME will exactly be the same as SYSDATE (which is right now) + 5 minutes, which is in the future.
Perhaps you'd rather set that condition to e.g. rows inserted during last 5 minutes (which makes more sense to me):
and MO.INSERT_TIME >= sysdate - INTERVAL '5' MINUTE
DATE + NUMBER where number can be fractional and is interpreted as days, and a minute is 1/(24*60) of a day...
Given:
INSERT INTO EP_ACCESS (PROFILE_ID, EPISODE_ID, START_TIMESTAMP, DISCONNECT_TIMESTAMP)
VALUES ('1', '1', TO_DATE('2020-01-01 00:00:01','yyyy/mm/dd hh24:mi:ss'), TO_DATE('2020-01-01 00:00:02','yyyy/mm/dd hh24:mi:ss'));
How can I select those who start_timestamp is in 2020?
You would use:
where start_timestamp >= date '2020-01-01' and
start_timestamp < date '2021-01-01'
Of course, you can use a timestamp literal if you prefer typing longer strings.
There are several options.
1 - Use BETWEEN
SELECT *
FROM EP_ACCESS
WHERE START_TIMESTAMP BETWEEN TO_DATE('2020-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND TO_DATE('2020-12-31 23:59:59', 'YYYY-MM-DD HH24:MI:SS')
or
SELECT *
FROM EP_ACCESS
WHERE START_TIMESTAMP BETWEEN DATE '2020-01-01'
AND DATE '2021-01-01' - INTERVAL '1' SECOND
2 - Use EXTRACT
SELECT *
FROM EP_ACCESS
WHERE EXTRACT(YEAR FROM START_TIMESTAMP) = 2020
3 - Use TRUNC
SELECT *
FROM EP_ACCESS
WHERE TRUNC(START_TIMESTAMP, 'YYYY') = DATE '2020-01-01'
Of these options, BETWEEN will probably provide the best performance as the other two require executing a function against the START_TIMESTAMP field in every row in the table.
I want to get all rows from my table, the table have one column with the following date type '14/07/2017 05:01:35 p.m.' between specific hours. Like between '00:01:00 am' and '01:00:00 am'.
I'm running Oracle Database 11g Release 2
select ID, CREATION_TIME
from my_table
where ID = 4 and
CREATION_TIME between to_date('29/04/2017 12:01:00', 'DD/MM/YYYY HH:MI:SS[AM]') and to_date('29/04/2019 01:00:00', 'DD/MM/YYYY HH:MI:SS[AM]')
order by creation_time asc;
I want to select hours instead of dates.
If you mean (from your last comment) that you want to get all records that are between the dates of Jan 1st 2019 and Apr 4th 2019, but only if the time portion of the recod is between 12:01AM and 1:00AM, then you could try this:
select ID, CREATION_TIME
from my_table
where ID = 4
and CREATION_TIME between to_date('01/01/2017', 'DD/MM/YYYY')
and to_date('04/04/2019', 'DD/MM/YYYY')
and CREATION_TIME BETWEEN TO_DATE(TO_CHAR(CREATION_TIME, 'MM/DD/YYYY') || ' 00:01:00', 'MM/DD/YYYY HH24:MI:SS')
AND
TO_DATE(TO_CHAR(CREATION_TIME, 'MM/DD/YYYY') || ' 01:00:00', 'MM/DD/YYYY HH24:MI:SS')
order by creation_time asc;
I run this query in oracle:
select TO_CHAR(parsed_on, 'DD-MON-YYYY HH24:MI:SS'), TO_CHAR(creation_date, 'DD-MON-YYYY HH24:MI:SS'),
(parsed_on - creation_date) * 1000
from hotels
where TO_CHAR(CREATION_DATE, 'dd/mm/yyyy') = TO_CHAR(SYSDATE, 'dd/mm/yyyy') and incoming_psd_id = 608423671;
and this is the result, where I was excepting 12 seconds instead of 8.4
10-NOV-2017 07:49:54 10-NOV-2017 07:37:46 8,42592592592
The correct expression for seconds in Oracle would be:
(parsed_on - creation_date) * 24*60*60
The difference is decimal days.
If you want minutes, then use:
(parsed_on - creation_date) * 24*60
select ( to_date('10-NOV-2017 07:49:54', 'DD-MON-YYYY HH:MI:SS') - to_date('10-NOV-2017 07:37:46', 'DD-MON-YYYY HH:MI:SS') )* 86400
from dual
Correctly gives 728 seconds.
And if you want to compare dates, you have this option:
where trunc(CREATION_DATE) = trunc(SYSDATE)
TRUNC cuts out the time portion of dates by default, whereas trunc(SYSDATE, YYYY) would cut it down to years only.
Have a SQL query on Oracle 11g which returns the count of whether a record having certain ID and status exists within +/- 15 minutes range in a table.
Now I wish to ignore the current date by adding a condition like AND TIMESTAMP < trunc(sysdate).
However, for cases where the record exists in todays date I wish to ignore the date comparison check in the query '2010-07-20 19:15:11' >= TO_CHAR(TIMESTAMP - (1/1440*15), 'YYYY-MM-DD HH24:MI:SS')
AND '2010-07-20 19:15:11' <= (TO_CHAR(TIMESTAMP + (1/1440*15), 'YYYY-MM-DD HH24:MI:SS'))
SELECT count(1) AS COUNT
FROM MASTER_ONE
WHERE ID='123' AND STATUS= 'ACTIVE'
AND '2010-07-20 19:15:11' >= TO_CHAR(TIMESTAMP - (1/1440*15), 'YYYY-MM-DD HH24:MI:SS')
AND '2010-07-20 19:15:11' <= (TO_CHAR(TIMESTAMP + (1/1440*15), 'YYYY-MM-DD HH24:MI:SS'))
UNION ALL
SELECT count(1) AS COUNT
FROM MASTER_TWO
WHERE ID='321' AND STATUS= 'ACTIVE'
AND '2010-07-20 19:15:11' >= TO_CHAR(TIMESTAMP - (1/1440*15), 'YYYY-MM-DD HH24:MI:SS')
AND '2010-07-20 19:15:11' <= (TO_CHAR(TIMESTAMP + (1/1440*15), 'YYYY-MM-DD HH24:MI:SS'))
How do I do this?
The first problem with your query is that you're doing a string comparison on the date. Use to_date instead of to_char and let Oracle help you out.
SELECT
to_date('2010-07-20 19:15:11', 'YYYY-MM-DD HH24:MI:SS') AS orig_date
, to_date('2010-07-20 19:15:11', 'YYYY-MM-DD HH24:MI:SS') - 1 / 24 / 4 AS fifteen_min_prior
, to_date('2010-07-20 19:15:11', 'YYYY-MM-DD HH24:MI:SS') + 1 / 24 / 4 AS fifteen_min_after
FROM dual;
Output:
ORIG_DATE FIFTEEN_MIN_PRIOR FIFTEEN_MIN_AFTER
------------------------- ------------------------- -------------------------
20-JUL-10 07:15:11 PM 20-JUL-10 07:00:11 PM 20-JUL-10 07:30:11 PM
Then use can use those dates in a BETWEEN condition in the predicate. See Oracle date "Between" Query.
I'm not quite clear what you mean by "However, for cases where the record exists in todays date I wish to ignore the date comparison check in the query." You'd just written that you want to exclude values from the current day. Either you're excluding today's records or you're not.
Ok, you can try something like this, if I understood you correctly:
SELECT count(1) AS COUNT
FROM MASTER_ONE
WHERE ID='123' AND STATUS= 'ACTIVE'
AND (timestamp > trunc(sysdate)
OR (timestamp < trunc(sysdate)
AND timestamp BETWEEN to_date(:yourInputDate,'DD/MM/YYYY HH24:MI:SS') - (1/1440*15)
AND to_date(:yourInputDate,'DD/MM/YYYY HH24:MI:SS') + (1/1440*15)))
UNION ALL
SELECT count(1) AS COUNT
FROM MASTER_TWO
WHERE ID='321' AND STATUS= 'ACTIVE'
AND (timestamp > trunc(sysdate)
OR (timestamp < trunc(sysdate)
AND timestamp BETWEEN to_date(:yourInputDate,'DD/MM/YYYY HH24:MI:SS') - (1/1440*15)
AND to_date(:yourInputDate,'DD/MM/YYYY HH24:MI:SS') + (1/1440*15)))
In this Select, you only apply the 15 minutes condition if your timestamp column has a date prior to sysdate.