Yesterday's date in where clase with HH:MM:SS - sql

In my query I currently have user enter datetime.
Current query
where TableT.STARTDATETIME >= To_Date('?DATE1?','MM-DD-YYYY HH24:MI:SS')
and TableT.STARTDATETIME <= To_Date('?DATE2?','MM-DD-YYYY HH24:MI:SS')
User would enter
for Date1: 10-02-2013 00:00:00
for Date2: 10-02-2013 23:59:59
Parameter :- ?DATE? & DATE2 is just a parameter for user to enter dates.
Need
How can I made sql automatically enter yesterday's date starting from 00:00:00 to 23:59:59?
I know I can use use something like sysdate-1 but not sure.

You could use
TRUNC(TableT.STARTDATETIME) = TRUNC(sysdate-1)
for this purpose to truncate both dates to the day on both side of the check. However, for this to be efficient, you'd need a function index on TRUNC(TableT.STARTDATETIME).
Maybe better in general from a performance aspect:
TableT.STARTDATETIME >= trunc(sysdate-1) AND TableT.STARTDATETIME < trunc(sysdate);
This includes yesterday 00:00:00 (the >= ), but excludes today 00:00:00 (the <).
Warning! Keep in mind, that for TIMESTAMP columns - while tempting because of its simplicity - don't use 23:59:59 as end time, as the 1 second time slot between 23:59:59 and 00:00:00 might contain data too - and this gap will leave them out of processing...

It would be:
where TableT.STARTDATETIME >= trunc(sysdate-1) and
TableT.STARTDATETIME < trunc(sysdate)
Avoid truncating the column value itself -- although you can place an index on Trunc(TableT.STARTDATETIME) you'd need another one to support time-based queries, and it's a fine way to obscure the distribution of values from the optimiser.
Have a look here for more info on date and timestamp arithmetic, and at the Trunc(datetime, format) function for other useful ways of manipulating dates.

Related

Best way to handle between in two dates in postgresql on timestamp

i am having date field in my table in the format of yyyy-mm-dd HH:MM:SS wanted to get records between 11-july-2020 inclusive 14-july-2020 but records are missing on 14th. Tries >= && < SYMMETRIC but non of them is working.
currently using select .... from employee where ... and created_on in between ?1 and ?2 . It is excluding record created on 14th.
I think you want:
where col >= '2020-07-11' and col < '2020-7-15'
Or, to express this using timestamps:
where col::timestamp >= '2020-07-11'::timestamp and
col::timestamp < '2020-07-14'::timestamp + interval '1 day'
Note that the higher end is one day later than 2020-07-14, so you can get all times on that day.
You can also use between as:
where col::date between '2020-07-11'::date and '2020-07-14'::date
But I discourage the use of between with date/time data types -- precisely because of the problem that you are having with the time component.
If your field has format yyyy-mm-dd HH:MM:SS it is a timestamp field not a date field. That makes a big difference in the comparison that needs to be done as #Gordon shows. If you compare a timestamp to a date(14-july-2020) the date will be turned into a timestamp with a time of 00:00:00:
select '07/14/2020'::timestamp;
timestamp
---------------------
2020-07-14 00:00:00
That means you will miss the timestamps on the 14th that fall after Midnight of 13/14th.

How to transform Oracle DateTime to Date

For instance, I have a datetime like this '2016-04-02 00:00:00' and another like this '2016-04-02 15:10:00'. I don't care about the time-part, I want them to match just by the date-part.
I have tried with date(), to_date, datepart, nothing works.
Do it like this:
where yourField >= the start of your date range
and yourField < the day after the end of your date range
Edit starts here:
While you could use trunc, as suggested by others, bear in mind that filtering on function results tends to be slow.
Truncating the date to day should do the trick. Documentation here:
https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions201.htm
For example
SELECT TRUNC(SYSDATE, 'DAY') FROM DUAL;
As others have said - there is no separate "date" data type in Oracle. A pure "date" is stored as a date with the time portion set to 00:00:00 (midnight at the beginning of the day), and TRUNC(date) will take any date and truncate the time to 00:00:00, so if you need to compare two dates you can write
where trunc(date_1) = trunc(date_2)
If your tables are very large and you need to do these comparisons often, this is not ideal, because wrapping column values within function calls (like date_1 within a TRUNC) prevents the use of an index you may have on the date_1 column. If you need to compare dates in two columns you may not have much of a choice, but if you compare to a fixed date (or something like SYSDATE) you may be better off with something like
where date_1 >= trunc(sysdate) and date_1 < trunc(sysdate) + 1
Here you are not using trunc on the column value, so if there's an index on the column, Oracle is free to use it - and trunc(sysdate) is computed only once, not for every single row. "+1" by the way means "add one day".
TO_DATE converts a string to a date; if you apply TO_DATE to a value that is already a legitimate date, you will get unexpected results because Oracle will first convert your true date to a string and then back to date again, and since these conversions require a date FORMAT for strings, and the formats Oracle assumes for conversion from date to string and from string to date may not match, .... you get the idea. As far as I know, DATE() (a FUNCTION) and DATEPART do not exist in Oracle; when you use a new language, keep Google close by and use it often.
If you input a date with no time component, for example TO_DATE('04-apr-2016, 'dd-mon-yyyy'), then the implicit time is 00:00:00 so you don't need to apply TRUNC() to it.
Good luck!

Sysdate Oracle to Run Based on Day

This is probably an easy question for most of you but how can I get this mask to run based on just the day?
If anyone knows Crystal Reports syntax, we have this and it works {PO_RECEIPTS.DATE_RECEIVED} = currentdate
However, when converting to Oracle SQL, how can I the standard: TO_CHAR
(SYSDATE, 'MM-DD-YYYY HH24:MI:SS') to become range so we can selected everything during the day, not just what matched the second in which the report was ran which it never will.
So something like Today from 00:00:00 to 23:59:59 ?
Thank you!
If PO_RECEIPTS.DATE_RECEIVED is a date column where all the times are set to midnight then you can do:
WHERE PO_RECEIPTS.DATE_RECEIVED = TRUNC(sysdate)
If the values have other times then you can use a range:
WHERE PO_RECEIPTS.DATE_RECEIVED >= TRUNC(sysdate)
AND PO_RECEIPTS.DATE_RECEIVED < TRUNC(sysdate) + 1
Truncating a date sets the time to midnight, by default, so TRUNC(sysdate) is midnight this morning. For the range you get all records equal to or later than midnight this morning, and less than midnight tomorrow - which is what TRUNC(sysdate) + 1 gives you, using normal Oracle datetime arithmetic.
You don't really want to convert it to a string with TO_CHAR(); you'd either have to convert all the column values to strings too (which is inefficient and prevents an index being used), or let the string be (implicitly) converted back to a date anyway. It's better to compare a column value with the same data type to reduce or avoid confusion.

Issue with date formatting SQL

SELECT LISTING_EOD.LOCATION, LISTING_EOD.APPTTIME, LISTING_EOD.PERSON_ID,
LISTING_EOD.FORENAME, LISTING_EOD.SURNAME, LISTING_EODS.STATUS,
LISTING_EOD.DBDATE
FROM DBNAME.LISTING_EOD LISTING_EOD;
This query returns a list of data processed today, I need to modify to check yesterday's data. I have tried add the below line of code, but it doesn't return anything. Does anyone know how I can achieve this?
where LISTING_EOD.DBDATE = '18-OCT-2012';
If you always want yesterday's data, rather than hard-coding the date you can use:
WHERE LISTING_EOD.DBDATE >= TRUNC(SYSDATE) - 1
AND LISTING_EOD.DBDATE < TRUNC(SYSDATE)
TRUNC(SYSDATE) gives you midnight this morning, so if run today it would give a range between 18-Oct-2010 00:00:00 and 18-Oct-2012 23:59:59.
It's generally not a good idea to use implicit date format masks; your original code assumes your NLS_DATE_FORMAT is set to DD-MON-YYYY, but that might not be correct now (if you're seeing the time in the existing select then it probably isn't), and may well not be in the future. Always use an explicit date format mask, like TO_DATE('18-OCT-2012', 'DD-MON-YYY'), to avoid ambiguity and unexpected behaviour.
If the field is actually VARCHAR2 rather than a DATE - which is bad - then you'll need to convert the date range to a string to get a match:
WHERE LISTING_EOD.DBDATE >= TO_CHAR(TRUNC(SYSDATE) - INTERVAL '1' DAY, 'DD-MON-YYYY HH24:MI:SS')
AND LISTING_EOD.DBDATE <= TO_CHAR(TRUNC(SYSDATE) - INTERVAL '1' SECOND, 'DD-MON-YYYY HH24:MI:SS')
That will work for a single day, just, but you'd have problems looking for a date range. It's much better and safer to store data in a column of the appropriate type.
Dates in Oracle by default contain time as well. If you just specify '18-OCT-2012', it will only match 18-OCT-2012 00:00:00'. One way to get around this is to format your database date to what you are comparing it to, e.g. to_char(LISTING_EOD.DBDATE, 'DD-MON-YYYY') and compare this to '18-OCT-2012'. This comparison will disregard time completely.
If you had a date variable to compare with instead of a string, format this using the same date mask used for the database date. This also gets around any assumptions abut default date format on the database in question.
I realised the 'table' I was querying was a view, examined it inside sqldeveloper, and added '-1' to the sysdate. This query then returned the previous days results.
I successfully retrieved the correct data, thanks for all help received.

How to find time of day or range in TIMESTAMP column

I have a list of events with begin and end timestamps in GMT UTC+0. The column is type DATE but has time as well (not designed by me).
The begin timestamp is plainly indexed
I need to find events the occur between, say, 06:00 and 22:00 Localtime which is Eastern Daylight Time UTC-4. on any day between March 31th and April 2nd.
The Only way I've found to do it is convert it TO_CHAR() then. It's also not using the index because it's using TO_CHAR function.
Here's what I go so far.
TO_CHAR(e.begin_time,'HH24:MI') >= TO_CHAR(FROM_TZ(TO_TIMESTAMP('06:00','HH24:MI'),'US/Eastern') AT TIME ZONE '+00:00','HH24:MI') AND
TO_CHAR(e.begin_time,'HH24:MI') <= TO_CHAR(FROM_TZ(TO_TIMESTAMP('22:00','HH24:MI'),'US/Eastern') AT TIME ZONE '+00:00','HH24:MI') AND
TO_CHAR(e.begin_time,'DDMMYYYY HH24:MI') >= TO_CHAR(FROM_TZ(TO_TIMESTAMP('Mar-31-2012 00:00','MON-DD-YYYY HH24:MI'),'US/Eastern') AT TIME ZONE '+00:00','DDMMYYYY HH24:MI') AND
TO_CHAR(e.begin_time,'DDMMYYYY HH24:MI') <= TO_CHAR(FROM_TZ(TO_TIMESTAMP('Apr-2-2012 23:59','MON-DD-YYYY HH24:MI'),'US/Eastern') AT TIME ZONE '+00:00','DDMMYYYY HH24:MI')
Thanks in advance,
Dan
The performance of the following might not be what's wanted, but if you cast the DATE value to a TIMESTAMP you can use the EXTRACT function in a manner similar to:
SELECT *
FROM your_table e
WHERE e.BEGIN_TIME BETWEEN TO_DATE('31-MAR-2012 00:00:00',
'DD-MON-YYYY HH24:MI:SS')
AND TO_DATE('02-APR-2012 23:59:59',
'DD-MON-YYYY HH24:MI:SS') AND
EXTRACT(HOUR FROM CAST(e.BEGIN_TIME AS TIMESTAMP)) BETWEEN 6 AND 22
Share and enjoy.
When trying to grab data based on a portion of a date field, of course the index will not be used. there just ain't any workaround to that. You could look into adding a function-based index, however, to index on the minutes of the day in EST. Or, perhaps, add a new column to hold minutes_est, have it populated by an insert/update trigger and then base your query on that.
If this is a regularly used query, and the performance of a full table scan isn't cutting it, then yes - I think this is one of those times where you might need to do some redesign based on your needs for this.