use of trunc date in sql - sql

can anyone explain me the working of trunc(date) function in oracle.
my query is as below.
select trunc(tran_date) from tablename;
i have not passed any format type.
If i compare the date present in table without having trunc(date) it will not give any output.
and if compare date table with trunc(date) it will give me proper ouptut.
please explain how it is working.
and is there any replacement for trunc function as it is taking too much time.

trunc(tran_date) returns the date portion of the date column with no time component (which is midnight at the start of the day).
Despite its name, the date data type in Oracle includes the time. This is even more confusing because you sometimes do not see the time in the result set (depending on how you access the data).
The dates that you are comparing to have no time component. So, the comparison works with trunc(). But the time component on tran_date prevents the comparison from working without trunc().

Related

Cannot pull correct time range

After executing this query
AND TRUNC(ITD.TRAN_DATE)>= '02-APR-18'
AND TO_CHAR(ITD.TRAN_DATE,'HH24MI')>='0600'
AND TRUNC(ITD.TRAN_DATE)<= '03-APR-18'
AND TO_CHAR(TRUNC(ITD.TRAN_DATE+1),'HH24MI')<='0030'
Everything after 6AM for April 2nd will show, but also times after 12:30AM the next day shows. What am I doing wrong here?
When we truncate a date we remove the time element. Consequently, a mask of 'HH24:MI' will return '00:00' which means that this will always be true regardless of the actual time component of ITD.TRAN_DATE:
AND TO_CHAR(TRUNC(ITD.TRAN_DATE+1),'HH24MI')<='0030'
Probably what you should do is something more straightforward, such as
where itd.tran_date >= date '2018-04-02' + (6/24)
and itd.tran_date <= date '2018-04-03' + (1/48)
Here's a SQL Fiddle demo comparing your WHERE clause with my suggestion.
Not sure what you want. Maybe this:
and to_char(itd.tran_date, 'YYYYMMDD-HH24MISS')
between '20180402-0600'
and '20180403-0030'
If so however, and if the table have many rows and tran_date is an indexed column, this might be a lot faster:
and itd.tran_date
between to_date('20180402-0600','YYYYMMDD-HH24MI')
and to_date('20180403-0030','YYYYMMDD-HH24MI')
In your question you assume the date_format to be DD-MON-YY. This might be the case now, for the environment you have today, but might not be so always. So it's good practice to use to_char or to_date on DATE values or strings.

Sql Query using 'Like' is giving results but using '=' does not returns any result in Oracle

The Query using LIKE :(This query when fired gives the desired result)
select * from catissue_audit_event where event_timestamp like '16-DEC-14'
But when using query with '=' results in an empty resultset
select * from catissue_audit_event where event_timestamp='16-DEC-14'
Here event_timestamp is of type Date
Strange thing is that the query runs for other dates such as:
select * from catissue_audit_event where event_timestamp='15-DEC-14'
What can be the issue? I already checked for leading and trailing spaces in the data
Output after running the first query:
In Oracle a DATE (and of course a TIMESTAMP) column contains a time part as well.
Just because your SQL client is hiding the time, doesn't mean it isn't there.
If you want all rows from a specific day (ignoring the time) you need to use trunc()
select *
from catissue_audit_event
where trunc(event_timestamp) = DATE '2014-12-16';
Be aware that this query will not use an index on the event_timestamp column.
You should also not rely on implicit data type conversion as you do with the expression event_timestamp = '16-DEC-14. That statement is going to fail if I run it from my computer because of different NLS settings. Always use a proper DATE literal (as I have done in my statement). If you don't like the unambiguous ISO date, then use to_date():
where trunc(event_timestamp) = to_date('16-12-2014', 'dd-mm-yyyy');
You should avoid using month names unless you know that all environments (which includes computers and SQL clients) where your SQL statement is executed are using the same NLS settings. If you are sure, you can use e.g. to_date('16-DEC-14', 'dd-mon-yy')
The reason why this is different is different to the solution to your issue.
The solution to your issue is to stop performing date comparisons by implicit conversion to a string. Convert your string to a date to perform a date comparison:
select * from catissue_audit_event where event_timestamp = date '2014-12-16'
I cannot stress this enough; when performing a date comparison only compare dates.
Your column EVENT_TIMESTAMP is being implicitly (this is bad) converted to a date in accordance with your NLS_DATE_FORMAT, which you can find as follows:
select * from nls_session_parameters
This governs how date-data is displayed and implicitly converted. The reason why LIKE works and and = doesn't is because your NLS_DATE_FORMAT is masking additional data. In other words, your date has a time component.
If you run the following and then re-select the data from your table you'll see the additional time component
alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss'
Thus, if you want all the data for a specific date without constraint on time you'll need to remove the time component:
select * from catissue_audit_event where trunc(event_timestamp) = date '2014-12-16'
have you tried matching the event_timestamp format example: DD-MMM-YY with the date that you are passing?

Fetching the records which are having all time stamp columns

I am trying to fetch the records which are having all time stamp columns.
I am using the following query to fetch the products that are created between the final date and (final date - 30) days, i.e products created during the last 30 days that fall in the 'final date' range.
I have products that are created on 30-OCT-2014. For the same products, the initiated date is 12-NOV-2014. However they are not being fetched when I using the below query.
SELECT A.ROW_ID,
A.PROD_NAME
FROM PROD A,
PROD_REL B
WHERE A.ROW_ID = B.PAR_ROW_ID
AND TO_DATE(A.CREATED_DT,'YYYY-MM-DD') BETWEEN (TO_DATE(B.FINAL_DATE,'YYYY-MM-DD') - 30)
AND (TO_DATE(B.FINAL_DATE,'YYYY-MM-DD'));
So, could you please let me know if I am missing something?
Here is a link to a SQLFiddle that demonstrates the problem.
… or just fix your format string TO_DATE(A.CREATED,'DD-MON-YYYY')
SQL Fiddle
Storing dates as DATE, is , of course, always a good starting point.
Since your data types are all dates, there is no need to use to_date. It's harmful, in fact, since to_date doesn't take a date as a parameter. Oracle has to do an implicit conversion from a date to a string, using your session's NLS_DATE_FORMAT which gets passed in to to_date and converted back to a date using the explicit format mask you specified. If the two conversions aren't using the same format mask, bad things happen.
Your WHERE clause just needs to be
AND a.created_dt BETWEEN b.final_date - 30
AND b.final_date
If I make that change, your SQLFiddle returns two rows

Oracle SQL: Why does last_day(SYSDATE) need to_date()?

Yesterday, I changed one of our queries to pivot on sysdate.
In my where's and joins I used last_day(SYSDATE) at first; however, this returned no data (This was filtering on a time_key column with date values).
When I changed the query to to_date(last_day(SYSDATE)) the query returned data as it should.
I have heard that SYSDATE contains time as well as a date (Although, I don't see this in
a SELECT SYSDATE FROM DUAL;).
Can anyone elaborate on why I need to call to_date() on my last_day(SYSDATE)? Shouldn't I have already had a date value?
This is a big long for a comment.
The expression last_day(sysdate) works fine. Here is a SQL Fiddle.
My guess is that the problem you are experiencing is that the time component is passed through, and you don't want the time. In that case, just use trunc(). The following are equivalent:
trunc(last_day(sysdate))
last_day(trunc(sysdate))

Unknown SQL coding issue in Oracle SQL Developer

I'm writing an SQL statment that is supposed to do a count based on a date range. But, for some reason no data is being returned. Before I try and filter the count with my date range, everything works fine. Here is that code.
SELECT
CR.GCR_RFP_ID
,S.RFP_RECEIVED_DT
,CR.GCR_RECEIVED_DT
,CT.GCT_LOB_IND
FROM ADM.GROUP_CHANGE_TASK_FACT CT
JOIN ADM.B_GROUP_CHANGE_REQUEST_DIM CR
ON CR.GROUP_CHANGE_REQUEST_KEY = CT.GROUP_CHANGE_REQUEST_KEY
JOIN ADM.B_RFP_WC_COVERAGE_DIM S
ON S. RFP_ID = CR.GCR_RFP_ID
WHERE CT.GCT_LOB_IND = 'WC'
AND CR.GCR_CHANGE_TYPE_ID IN ('10','20','30','50','60','70','80','90','100','110',
'120','130','140', '150','160','170','180','190','200',
'210','220','230','240','260','270','280','300','310',
'320','330','340','350','360','370','371','372')
AND S.RFP_AUDIT_IND = 'N'
AND S.RFP_TYPE_IND = 'A'
The date field I'm using is called CR.GCR_RECIEVED_DT. This is a new field a in the db and all the records are 01-JAN-00. But I'm still doing the count just to make sure I can grab the data. Now, I added this line:
AND CR.GCR_RECEIVED_DT LIKE '01-JAN-00'
just as a random test thing. I know all the dates are the same. And it works fine, no issues. So I remove that line and replace it with this:
AND CR.GCR_RECEIVED_DT BETWEEN '31-DEC-99' AND '02-JAN-00'
I used this small range to keep it simple. But even though 01-JAN-00 deffinetly falls between those two dates, no data is returned. I have no idea why this is happening. I even tried this line to:
AND CR.GCR_RECEIVED_DT = '01-JAN-00'
and I still don't get data returned. It only seems to work with LIKE. I have checked and the field is a date type. Any help wold be much appreciated.
If your NLS_DATE_FORMAT is set to DD-MON-YY then the apparent discrepancy between the first two results can be explained.
When you use LIKE it implicitly converts the date value on the left-hand side to a string for the comparison, using the default format model, and then compares that to the fixed string; and '01-JAN-00' is like '01-JAN-00'. You're effectively doing:
AND TO_CHAR(CR.GCR_RECEIVED_DT, 'DD-MON-YY') LIKE '01-JAN-00'
Using LIKE to compare dates doesn't really make any sense though. When you use BETWEEN, though, the left-hand side is being left as a date, so you're effectively doing:
AND CR.GCR_RECEIVED_DT BETWEEN TO_DATE('31-DEC-99', 'DD-MON-YY')
AND TO_DATE('02-JAN-00', 'DD-MON-YY')
... and TO_DATE('31-DEC-99', 'DD-MON-YY') is December 31st 2099, not 1999. BETWEEN only works when the first value is lower than the second (from the docs, 'If expr3 < expr2, then the interval is empty'). So you're looking for values bwteen 2099 and 2000, and that will always be empty. If your date model was DD-MON-RR, from the NLS parameter or explicitly via TO_DATE, then it would be looking for values between 1999 and 2000, and would find your records.
Your third result is a little more speculative but suggests that the values in your GCR_RECEIVED_DT field have a time component, or are not in the century you think. This is similar to the LIKE version, except this time the fixed string is being converted to a date, rather than the date being converted to a string; effectively:
AND CR.GCR_RECEIVED_DT = TO_DATE('01-JAN-00', 'DD-MON-YY')
If they were at midnight on 2000-01-01 this would work. Because it doesn't that suggests they are either some time after midnight, or maybe more likely - since you're using a 'magic' date in your existing records - they are another date entirely, quite possibly 1900-01-01.
Here are SQL Fiddles for just past midnight and 1900.
If the field will eventually have a time component for new records you might want to structure the condition like this, and use date literals to be a bit clearer (IMO):
AND CR.GCR_RECEIVED_DT >= DATE '2000-01-01'
AND CR.GCR_RECEIVED_DT < DATE '2000-01-02'
That will find any records at any time on 2000-01-01, and can use an index on that column if one is available. BETWEEN is inclusive, so using BETWEEN DATE '2000-01-01' AND '2000-01-02' would include any records that are exactly at midnight on the later date, which you probably don't want.
Whatever you end up doing, avoid relying on implicit conversions using NLS_DATE_FORMAT as one day it might not be set to what you expect, causing potentially data-corrupting or hard to find bugs; and specify the full four-digit year in the model if you can to avoid ambiguity.
try something like this:
WHERE TRUNC(CR.GCR_RECEIVED_DT) = TO_DATE('01-JAN-00','DD-Mon-YY')
TRUNC without parameter removes hours, minutes and seconds from a DATE.