Issue with date formatting SQL - 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.

Related

sql condition to not include 4712 date

I always have an issue with date transformation. Can someone guide and help me understanding the date transformation.
I am using the below code in Oracle Fusion HCM Extract tool and I am getting the correct output
APPROVAL_STATUS_CD='APPROVED'
AND ABSENCE_STATUS_CD in ('SUBMITTED','ORA_WITHDRAWN')
and typetl.name != 'Banked Time - Disbursement'
and (TO_DATE(trunc(start_date) ,'YYYY-MM-DD')
>= TO_DATE((select trunc((sysdate),'month') as FirstDay from dual),'YYYY-MM-DD'))
but it is giving me data that has start_date as '4712-12-31' as well. I do not want this in my output. as soon as i add the below condition -
and (TO_DATE(trunc(start_date) ,'YYYY') != TO_DATE('YYYY','4712'))
I am not getting any output. How do I restrict the 4712 date in the start_Date column i.e. whichever data has 31-12-4712 in start_date should not come in output.
Assuming that there will be no higher values then you want:
AND start_date < DATE '4712-12-31'
Note: NEVER use TO_DATE on a value that is already a DATE data type.
Which would make your query:
WHERE APPROVAL_STATUS_CD='APPROVED'
AND ABSENCE_STATUS_CD in ('SUBMITTED','ORA_WITHDRAWN')
AND typetl.name != 'Banked Time - Disbursement'
AND start_date >= TRUNC(SYSDATE,'MM')
AND start_date < DATE '4712-12-31'
If you don't supply all the date elements then Oracle defaults to the first day of the current month; so TO_DATE('YYYY','4712') evaluates to 4712-04-01, not 4712-12-31 or 4712-01-01.
If you want a fixed date then it's easier to use a literal: DATE '4712-12-31', or possibly - given the range of valid dates Oracle allows - you really want DATE '-4712-01-01' (or DATE '-4712-12-31'). I'd check the full actual value you have in your data with TO_CHAR(start_date, 'SYYYY-MM-DD'). That will show you if it's BC/BCE (with a negative value) or AD/CE (with a positive value).
Also, do not use TO_DATE() for a value that is already a date; it might work, or it might do odd things. You don't need to do that. When you do TO_DATE(trunc(start_date) ,'YYYY-MM-DD') you're implicitly doing TO_DATE(TO_CHAR(trunc(start_date), <NLS_DATE_FORMAT>) ,'YYYY-MM-DD') - which relies on the current session's NLS settings. Even if it works today, for you, it will break one day someone else.
Just trunc(start_date) and `trunc(sysdate, 'month') is enough. Though there's no point truncating the start_date really - if the truncated value is after the start of the month, so is the original non-truncated value.

Using the To_Date function is not converting to the expected format

I'm trying to convert a char (output from a substr operation) into a dateTime format using TO_DATE with the following format - hh24:mi:ss.
The output of the substr looks fine but as soon as I run it through the TO_DATE function it converts every row for this column into 01-MAR-22.
To demonstrate I have the following:-
SUS_TIME2 shows what I get back from the SUBSTR and it looks fine at this point. SUS_TIME3 then shows what I get back after running it through the TO_DATE function, this where it converts it to 01-MAR-22
,SUBSTR((s.resolve_date-suspend_date),-16,9) sus_time2
,TO_DATE(SUBSTR((s.resolve_date-suspend_date),-16,9), 'hh24:mi:ss') sus_time3
Can anyone see what's going on here please? Thanks
Dates are stored in an internal representation and do not have any intrinsic format. What you are seeing is how your client is choosing to format the actual date value as a string for display, using your session's NLS_DATE_FORMAT setting (not always the case, but this is SQL Developer, so it is here.)
When you call to_date() with only the time components it defaults the date part to the first day of the current month, which is why you are seeing March 1st. That is a bit buried in the documentation:
If you specify a date value without a time component, then the default time is midnight. If you specify a date value without a date, then the default date is the first day of the current month.
But it is setting the time properly on that date, which you can see by either explicitly converting the date back to a string:
to_char(<your date>, 'YYYY-MM-DD HH24:MI:SS')
or by changing your session:
alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'
db<>fiddle
But you should not rely on NLS settings for anything except ad hoc queries; someone else running your code may have different settings. And only convert back to a string at the last moment when you have to display the value in a particular format - store it and pass it around as a native date.
Oracle doesn't have a time-only data type, so if you really only care about the time part then you can use a date (either defaulting to current month, or using an explicit fixed date) and ignore the date part; or potentially use an interval; or use the number of seconds the time represents (i.e. 0-86399). Which is suitable depends on what you'll use the value for.
It looks like you might be substringing the result of subtracting two timestamps; in which case (a) you already have an interval, and (b) you probably need to allow for that difference to span more than one day. You can also extract the individual time components directly from an interval value. So I'd question whether your approach is really appropriate.
You appear to be calculating s.resolve_date-suspend_date which gives you an INTERVAL DAY TO SECOND data type (implying that one or both of s.resolve_date or suspend_date is a TIMESTAMP data type) and then using SUBSTR to extract the time component of the data type and trying to convert that to a date and then display the time component.
Don't do that as using SUBSTR is fragile as it depends on the number of decimal places that the INTERVAL has which, in turn, will depend on the number of fractional seconds that the TIMESTAMP values have.
Just pick a date and add the interval to it and then format it as string to display it:
SELECT s.resolve_date,
suspend_date,
TO_CHAR(
DATE '1900-01-01' + (s.resolve_date-suspend_date),
'hh24:mi:ss'
) sus_time
FROM table_name s
Which, for the sample data:
CREATE TABLE table_name (resolve_date, suspend_date) AS
SELECT CAST(SYSTIMESTAMP AS TIMESTAMP(6)),
CAST(TRUNC(SYSTIMESTAMP) AS TIMESTAMP(6))
FROM DUAL;
Outputs:
RESOLVE_DATE
SUSPEND_DATE
SUS_TIME
2022-03-25 12:59:15.223445
2022-03-25 00:00:00.000000
12:59:15
From your comment:
all i'm trying to do is format the data so that when it's exported to Excel sorting works correctly.
That really is an XY-problem. You can solve it in Excel by either specifying the column format as a time when you import the data into Excel or right-click on the column header and "Format" the column picking the "time" data type with the correct format model.
You can also output the time as a fraction of a day with a numeric data type and then Excel can format it as the correct time using either:
SELECT s.resolve_date,
suspend_date,
MOD(CAST(s.resolve_date AS DATE)-CAST(suspend_date AS DATE), 1) AS sus_time
FROM table_name s;
or
SELECT s.resolve_date,
suspend_date,
TO_CHAR(DATE '1900-01-01' + (s.resolve_date-suspend_date), 'SSSSS')
/ 86400 AS sus_time
FROM table_name s
Which both output:
RESOLVE_DATE
SUSPEND_DATE
SUS_TIME
2022-03-25 13:16:40.204461
2022-03-25 00:00:00.000000
.5532407407407407407407407407407407407407
Which may not be human readable in that format but Excel will reformat it in a time column to 13:16:40.
db<>fiddle here

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.

Epoch date in the form 'YYYY-MM-DD"T"HH24:MI:SS"Z"'

I am new to SQL and have run into a problem. I want to have the epoch date i.e. 1970-01-01T00:00:00Z in this mentioned format.
I cannot use it as a constant (i.e. '1970-01-01T00:00:00Z') for programming reasons. I need a statement that gives this as an output. I have used this:
select to_char(TRUNC(add_months(sysdate,-555),'MM'), 'YYYY-MM-DD"T"HH24:MI:SS"Z"') from dual;
But the only problem with this statement is it will not give me the date I want next month i.e. it is month specific it will only work for April 2016. But I need a the date to always remain 1970-01-01T00:00:00Z.
Thanks in advance for the help.
PS: I am using Oracle SQL Developer (if that matters).
You can just do:
select '1970-01-01T00:00:00Z' from dual;
Or if you want to have it processed for some reason, which seems like pointless overhead:
select to_char(date '1970-01-01', 'YYYY-MM-DD"T"HH24:MI:SS"Z"') from dual;
Either will give you the string you want. But it is a string, not a date. If you want it as a proper data type (which I don't think you do, but maybe this is for comparison) it needs to be a timestamp with time zone, which you can get with:
select timestamp '1970-01-01 00:00:00 UTC' from dual;
Well this might not be the most elegent way but it is a way that will work:
select regexp_substr('1970-01-01T00:00:00Z','^....................',1,1) from dual;