I’m experiencing some issues while using the Current_Date function in a simple query and I haven’t been able to figure out why. I’m working in an Oracle 12c environment using Oracle SQL Developer 3.2.
My original query looks something like this:
select * from Inventory where Placement_End_Dt >= Current_date
The above works fine except it doesn’t pick up records where Placement_End_Dt is today (14th May 18)
I attempted to simplify the query as follows, but this also returns nothing
select * from Inventory where Placement_End_Dt = Current_date
However when I apply date formatting as follows, it works:
select * from Inventory where to_char(Placement_End_Dt, 'DD-MM-YYYY') = to_char(Current_date, 'DD-MM-YYYY')
Then I try and expand on this to revert to my original query to select all records with an end date from today onwards:
select * from Inventory where to_char(Placement_End_Dt, 'DD-MM-YYYY') => to_char(Current_date, 'DD-MM-YYYY')
This fails spectacularly because it selects records with a Placement_End_Dt past, present and future!
The Placement_End_Dt columns is defined as an Oracle DATE data type
Would appreciate some input on how I can get this query to work.
When using to_char you are comparing strings.
to_char(date '2000-01-20', 'DD-MM-YYYY') > to_char(date '2018-05-14', 'DD-MM-YYYY')
because '20-01-2000' is greater than '14-05-2018', because of the first letters in the strings: '2' > '1'.
And CURRENT_DATE is hardly ever used, because it uses your computer's time, rather than the database time, so you can easily be some hours off. Use SYSDATE instead.
I would suggest using this query
select * from Inventory where trunc(Placement_End_Dt) = trunc(sysdate);
Oracle Date columns also store a timestamp by default, so unless the records were the same down to the second, they won't match. When you use trunc() on a date column, it truncates the timestamp and leaves just the date.
Try this, it will return the rows for present days and future days.
select * from Inventory where trunc(Placement_End_Dt) >= trunc(sysdate);
Related
I am looking for a way to match a date, with the one related to records on my db.
I know how to match strings with the LIKE operator, but it doesn't work for dates; unless I search just for a number (say all records at 10, all records from the 21st and so on). As soon as I put minutes for example, the search with LIKE return no records.
How do you actually search for partial date? My objective is to find all records newer than a partial date; in the current day.
select * from CLIENTS where CLOSING like '%12:30%'
This won't match anything; but if I use just 12 or 30, it works....although it is not doing what I want.
Do I have to convert date in strings? I get a partial date from another process, and I would like to match all the records newer than the partial date.
Try this query
select * from CLIENTS where
TO_CHAR(CLOSING , 'dd-mm-yy hh24:mi:ss') like '%12:30%'
or
select * from CLIENTS where
TO_CHAR(CLOSING , 'hh24:mi') = '12:30'
If you want loans more recent than today at 12:30pm, you are best served to use date arithmetic rather than relying on string conversion
SELECT *
FROM clients
WHERE closing >= trunc(sysdate) + interval '12' hour + interval '30' minute;
or
SELECT *
FROM clients
WHERE closing >= trunc(sysdate) + 12.5/24
Here, trunc(sysdate) returns today at midnight. Then you can either add a fractional number of days (1/24 adds one hour so 12.5/24 takes you to 12:30pm) or you can add one or more intervals (you could use to_dsinterval as well to create the interval).
I have a table called CYCLING_ACCIDENTS_2 containing a TIMESTAMP(6) column called ACC_DATE_TIME , this is an example of how the date is stored 31-MAY-12 16.45.00.000000, I would like to know how I can query just the time in such a date format so that I can have a time interval for all years I have (2005-2012) but just restricted to certain times in the day. I tried many functions but all I've got so far are syntax errors, I tried to search on the web but I can' t see anything appropriate to my case. Could anyone help?
Thanks!
First of all, a timestamp is a number, not a string. So the date is displayed by default as 31-MAY-12 16.45.00.000000, but it is actually the amount of microseconds since 1970 I believe.
If you want to select just the time part use to_char()
select to_char(acc_date_time, 'hh24:mi') time
, count(*) occurences
from cycling_accidents_2
group by to_char(acc_date_time, 'hh24:mi')
edit: I think this second query actually answers your question:
select *
from cycling_accidents_2 ca
where to_char(ca.acc_date_time, 'hh24:mi') between '10:00' and '18:00'
and ca.acc_date_time >= to_timestamp('01-01-2005', 'dd-mm-yyyy')
and ca.acc_date_time < to_timestamp('01-01-2013', 'dd-mm-yyyy')
SELECT * FROM CYCLING_ACCIDENTS_2 WHERE
(EXTRACT(YEAR FROM ACC_DATE_TIME) BETWEEN 2005 AND 2012)
AND
(EXTRACT(HOUR FROM ACC_DATE_TIME) BETWEEN 10 AND 18)
I'm looking for a way to determine if a timestamp falls between two times, regardless of the date in that timestamp. So for example, if the time in the timestamp falls between '00:00:00.000' (midnight) and '01:00:00.000' (1 A.M.), I'd want to select that row regardless of the particular date.
I've tried lots of different variations on the to_char and to_date functions, but I keep getting errors. Coming from Informix, Oracle seems much more complicated.
The thing closest to "correct" (I think) that I've tried is:
SELECT *
FROM my_table
WHERE SUBSTR(TO_CHAR(my_timestamp), 10) > '00:00:00.000'
AND SUBSTR(TO_CHAR(my_timestamp), 10) < '01:00:00.000'
... But nothing works. Any tips or tricks?
I found a way to do it, but I'd still prefer something a little less hacky, if it exists.
SUBSTR(SUBSTR(TO_CHAR(my_timestamp), 11), 0, 12) > '01.00.00.000'
Your solution looks correct to me except I haven't tried substr function. This is what I used in one of my previous project:
select * from orders
where to_char(my_timestamp,'hh24:mi:ss.FF3')
between '00:00:00.000' and '01:00:00.123';
Use TRUNC(my_timestamp, 'J') to remove the hours and get only the '2013-08-15 00:00:00.00'.
So:
WHERE my_timestamp - TRUNC(my_timestamp, 'J') > 0
AND my_timestamp - TRUNC(my_timestamp, 'J') < 1/24 ;
As a variation on #kubanczyk's answer, since these are timestamps you get an interval when you subtract a value from its truncated form:
select systimestamp - trunc(systimestamp) from dual;
SYSTIMESTAMP-TRUNC(SYSTIMESTAMP)
---------------------------------------------------------------------------
+000000000 09:46:46.589795
Which isn't very helpful. But if you're always looking for exact hours, as in your example, you can extract the hour number from that:
select extract (hour from systimestamp - trunc(systimestamp)) from dual;
EXTRACT(HOURFROMSYSTIMESTAMP-TRUNC(SYSTIMESTAMP))
-------------------------------------------------
9
So in your example you could use:
SELECT *
FROM my_table
WHERE EXTRACT(HOUR FROM my_timestamp - TRUNC(my_timestamp)) = 0
SQL Fiddle demo.
But, this will only be straightforward if the timeslots are exactly aligned with hours; otherwise you'd need to extract other elements too and the logic could get confusing, and #Ankit's approach will be simpler overall.
I have the following query:
select *
from mytable
where to_char(mydate,'mm/dd/yyyy') between ('05/23/2013')
and ('06/22/2013')
I need to change it to make dynamically so that I won't modify it every month from 05/23/2013 to 06/23/2013 for example:
('05/23/' + (select to_char(sysdate, 'yyyy') from dual))
but this is giving an error. Any suggestions?
What I need to do: Every month I need to run this query to get the records between 23rd of this month and 23rd of the last month.
Oracle uses || as the concatenation operator:
('05/23/' || (select to_char(sysdate, 'yyyy') from dual))
BTW, David is right. If you really want to compare string representations of dates (but why?), use a date format that is ordered the same way as dates:
to_char(mydate,'yyyy/mm/dd')
You're performing a comparison on strings, not on dates, so your code doesn't work the way you think it does.
Based on the string logic, "05/23/2000" is between "05/22/2013" and "06/24/2000".
Keep the data types as date and Oracle will get the comparison right.
Possibly what you want is:
select *
from my_table
where mydate >= add_months(trunc(sysdate,'MM'),-1)+22 and
mydate < trunc(sysdate,'MM')+22
but it's difficult to tell without a description of what the requirement actually is.
How about this one?
SELECT '(''05/23/'''||to_char(sysdate, 'yyyy')||'''' FROM DUAL
Have not testet because I have no Oracle database right now, needs checking for quote escapes...
Do you need exact days from the month? You can also substract days from sysdate:
SELECT (sysdate - 30) FROM DUAL
You may also use concat function
concat('05/23/', (select to_char(sysdate, 'yyyy') from dual))
I am trying to optimize a simple SQL query and was wondering if anyone has any suggestions. I am developing using Oracle SQL Developer (which I don't like) on an Oracle 11g database. The query I am using is:
SELECT count(*)
FROM my_table
WHERE my_date
BETWEEN TO_DATE('2012-5-09T05.00.00','YYYY-MM-DD"T"HH24:MI:SS')
AND TO_DATE('2012-5-10T04.59.59','YYYY-MM-DD"T"HH24:MI:SS')
AND my_code='33'
GROUP BY my_code;
Also, I want to be able to use this query dynamically by changing the part of the date to be whatever the current date is, but I want to be able to specify the hour. So I want to be comparing something like:
getdate() + 'T05.00.00'
I have no idea how to do this and the getdate() function doesn't seem to work in SQL Developer/I don't know how to use it correctly.
So what I'm looking for is optimization suggestions and pointers on how to just dynamically change the day-month-year part of the date I want to constrain my results to. Thanks!
To get current date, you can use SYSDATE. To add x number of hours to it, you can add x/24. So something like this:
Example: Get current date + 5 hours
SELECT SYSDATE + 5/24 FROM dual
So in your example:
SELECT count(*)
FROM my_table
WHERE my_date
BETWEEN sysdate
AND sysdate + 5/24 -- if you want 5 hours ahead, for example
AND my_code='33'
GROUP BY my_code;
If you want to be able to change the number of hours, you could make this code into a function, and pass in the hours and code as variables.
Something like this:
CREATE FUNCTION myfunc
(
p_num_hours INT
, p_my_code VARCHAR
) RETURN INT
AS
l_ret INT;
BEGIN
SELECT count(*)
INTO l_ret
FROM my_table
WHERE my_date
BETWEEN sysdate
AND sysdate + p_num_hours/24
AND my_code=p_my_code
RETURN l_ret;
END;
As an alternative to adding fractional days via expressions such as "5 / 24" you might want to use an INTERVAL constant. For example:
SELECT count(*)
FROM my_table
WHERE my_date BETWEEN (TRUNC(SYSDATE) + INTERVAL '5' HOUR)
AND (TRUNC(SYSDATE) + INTERVAL '1' DAY +
INTERVAL '5' HOUR - INTERVAL '1' SECOND) AND
my_code='33'
GROUP BY my_code
I like to use INTERVAL constants because it's quite clear what these constants represent. With the fractional-day constants I sometimes get confused ('course, I sometimes get confused, regardless... :-)
Share and enjoy.
If I understand correctly, something like
select count(*)
from my_table
where trunc(my_date) = trunc(sysdate)
and my_code = '33'
group by my_code;
or
select count(*)
from my_table
where my_date
between sysdate and sysdate + 5/24
and my_code = '33'
group by my_code;
HTH.
Alessandro