I have two columns which are both stored as 'MM/DD/YYYYY HH:MM:SS AM (or PM)'. I'm able to use 'TO_CHAR' to change it to 'MM/DD/YYYY' format, but after I get that, I only want the dates where both columns are not equal to each other (after the TO_CHAR). I used '!=' but this doesn't work and it still returns rows when both dates are equal to each other. I basically want the fields to ignore the times, and to only return the row if both dates are different.
Here was the query I was trying to run:
select r.project_name, to_char(r.created_on, 'MM/DD/YYYY'),
to_char(r.project_opened_on_date, 'MM/DD/YYYY')
from wh_project_repo r
where r.created_on != r.project_opened_on_date
Any help please?
It does not make sense to store dates as a string. But you are doing that.
Because you have strings, there is no need to convert to dates. How about doing:
select r.project_name, to_char(r.created_on, 'MM/DD/YYYY'),
to_char(r.project_opened_on_date, 'MM/DD/YYYY')
from wh_project_repo r
where substr(r.created_on, 10) <> substr(r.project_opened_on_date, 10)
The problem with your query, though, is that the manipulations are in the select. This does not affect what the where clause is comparing.
EDIT:
You could also compare the values as dates by doing:
where to_char(r.created_on, 'MM/DD/YYYY') <> to_char(r.project_opened_on_date, 'MM/DD/YYYY')
The issue isn't the string comparisons. The issue is that functions in the select don't affect the where.
Related
I have a column called received_dt_key in Varchar in the format DD-MM-YYYY (e.g. 30-07-2021).
I would like to select all from the table for dates between 31-12-2021 and 01-01-2022. I have tried version of the below query and a blank table is the output.
SELECT *
FROM SD_BDAY
WHERE to_char(to_date(RECEIVED_DT_KEY, 'DD-MM-YYYY')) > to_char(to_date('31-12-2021', 'DD-MM-YYYY'))
and to_char(to_date(RECEIVED_DT_KEY, 'DD-MM-YYYY')) < to_char(to_date('01-01-2022', 'DD-MM-YYYY'));
Don't compare dates as strings. Compare them as dates:
SELECT *
FROM SD_BDAY
WHERE to_date(RECEIVED_DT_KEY, 'DD-MM-YYYY') > to_date('31-12-2021', 'DD-MM-YYYY')
and to_date(RECEIVED_DT_KEY, 'DD-MM-YYYY') < to_date('01-01-2022', 'DD-MM-YYYY');
If you try to compare them as strings then you are looking for string that is greater than '31-12-2021' and less than '01-01-2022' and the string comparison will look at the first character and see if it can find a match which is greater than '3' and less than '0'; there can never be such a match so it is quite correct that when comparing as strings nothing is returned.
As pointed out by #AlexPoole in comments, even if you compare the values as dates (rather than strings) you will still never return a result as finding values that are greater than DATE '2021-12-31' and less than DATE '2022-01-01' would return all dates from 2021-12-31 00:00:01 to 2021-12-31 23:59:59; however, your values will always be converted with a midnight time component and, therefore, will never fall into that range so cannot be returned.
What you probably want is to use >= rather than > and then it would match values on 2021-12-31.
The best thing would be to store calendar dates in date data type column. Why else do you think Oracle designed that data type? This way you may create normal indexes on data data type columns, or, if needed, partition the table by that date column.
Still, if you insist in having the calendar dates stored like that, I think the below should work:
SELECT *
FROM SD_BDAY
WHERE to_date(RECEIVED_DT_KEY, 'DD-MM-YYYY') >
to_date('31-12-2021', 'DD-MM-YYYY')
and to_date(RECEIVED_DT_KEY, 'DD-MM-YYYY') <
to_date('01-01-2022', 'DD-MM-YYYY');
Thus you compare calandar dates with calendar dates, not varchar with varchar, as it results from the code you have written.
And what if in the varchar2 column there is somethibng that can't be converted to date? That is why it is best to use the date data type.
I have the following Oracle Query that is converting todays date and the date field from the table into the same format. However, when trying to compare the two they aren't coming up as equal.
CAST(dstamp As Date), TO_DATE(CURRENT_DATE,'dd-MON-YY HH24.MI.SS','NLS_DATE_LANGUAGE = American')
The cast is used on the field in my table, both these return.
However, when adding the following where statement no rows are returned. I can't work out why these wouldn't be classed as equal?
WHERE CAST(dstamp As Date) = TO_DATE(CURRENT_DATE,'dd-MON-YY HH24.MI.SS','NLS_DATE_LANGUAGE = American');
Any help appreciated.
If you are trying to check if dstamp belongs to the current day, I would suggest:
where dstamp >= trunc(sysdate) and dstamp < trunc(sysdate) + 1
Athough a bit more verbose, this will be more efficient than applying a date function on the column being compared. Using a function on a column in a predicate makes the query non-SARGable, ie it cannot take advantage of an existing index.
The date is ALREADY a date. You don't need to convert it. You may need to remove the time component. Does this do what you want?
WHERE TRUNC(dstamp) = TRUNC(sysdate)
I have a table with column(last_update_date) of data type is text.So I need to pass a date and select the greater than dates from the table.
I tried with below query,
select batch_uuid,result
from #this
where extract_status = 'success'
and last_update_date > '02/21/2019'
But above query is not working.
Any advice please.
You would need to convert both strings to dates to compare them:
select batch_uuid,result
from mytable
where
extract_status = 'success'
and to_date(last_update_date, 'mm/dd/yyyy') > to_date('02/21/2019', 'mm/dd/yyyy')
Note:
#this is not a valid table, I changed it to mytable
do consider storing dates in a date-like datatype; using a string datatype will bite you in many ways (to start with, using a function like to_date() defeats an existing index on the column)
I am writing the following query
SELECT
TO_CHAR(TO_DATE(data_elaborazione, 'YYYYMMDD') -
TO_DATE(DATA_INS_AGG_SDS, 'YYYYMMDD') )AS DateDiff
FROM
dual
I want to calculate the difference between the two dates, in days, but I get an error:
ORA-00904: "DATA_INS_AGG_SDS": invalid identifier
The same goes for data_elaborazione too. Data_elaborazione, DATA_INS_AGG_SDS are both varchar types that contain dates as varchar
The error you are getting is cause by you referencing columns on dual that do not exist. You'll need to select these columns from the tables they actually exist in. As for your date arithmetic, it should return a number, which does not require TO_CHAR to display, unless you have some specific formatting concerns. Here is an example of date arithmetic. The second date value has a time component. So, the two columns due the date arithmetic and display the result, the second essentially rounds down to just get the number of days to an even integer value.
Please read the comments about data types. You should always work with values in their correct data types. Avoid storing either dates or numbers as strings in the DB.
-- start test_data
with some_data(begin_date, end_date) as
(select to_date('02/15/2017','MM/DD/YYYY'), to_date('04/03/2017 09:34:12','MM/DD/YYYY HH24:MI:SS') from dual)
-- end test data
select end_date - begin_date as num_days_diff_w_time,
FLOOR(end_date - begin_date) as num_days_diff_wo_time
from some_data;
First, I am aware that this question has been posted generally Equals(=) vs. LIKE.
Here, I query about date type data on ORACLE database, I found the following, when I write select statment in this way:
SELECT ACCOUNT.ACCOUNT_ID, ACCOUNT.LAST_TRANSACTION_DATE
FROM ACCOUNT
WHERE ACCOUNT.LAST_TRANSACTION_DATE LIKE '30-JUL-07';
I get all rows I'm looking for. but when I use the sign equal = instead :
SELECT ACCOUNT.ACCOUNT_ID, ACCOUNT.LAST_TRANSACTION_DATE
FROM ACCOUNT
WHERE ACCOUNT.LAST_TRANSACTION_DATE = '30-JUL-07';
I get nothing even though nothing is different except the equal sign. Can I find any explanation for this please ?
Assuming LAST_TRANSACTION_DATE is a DATE column (or TIMESTAMP) then both version are very bad practice.
In both cases the DATE column will implicitly be converted to a character literal based on the current NLS settings. That means with different clients you will get different results.
When using date literals always use to_date() with(!) a format mask or use an ANSI date literal. That way you compare dates with dates not strings with strings. So for the equal comparison you should use:
LAST_TRANSACTION_DATE = to_date('30-JUL-07', 'dd-mon-yy')
Note that using 'MON' can still lead to errors with different NLS settings ('DEC' vs. 'DEZ' or 'MAR' vs. 'MRZ'). It is much less error prone using month numbers (and four digit years):
LAST_TRANSACTION_DATE = to_date('30-07-2007', 'dd-mm-yyyy')
or using an ANSI date literal
LAST_TRANSACTION_DATE = DATE '2007-07-30'
Now the reason why the above query is very likely to return nothing is that in Oracle DATE columns include the time as well. The above date literals implicitly contain the time 00:00. If the time in the table is different (e.g. 19:54) then of course the dates are not equal.
To workaround this problem you have different options:
use trunc() on the table column to "normalize" the time to 00:00
trunc(LAST_TRANSACTION_DATE) = DATE '2007-07-30
this will however prevent the usage of an index defined on LAST_TRANSACTION_DATE
use between
LAST_TRANSACTION_DATE between to_date('2007-07-30 00:00:00', 'yyyy-mm-dd hh24:mi:ss') and to_date('2007-07-30 23:59:59', 'yyyy-mm-dd hh24:mi:ss')
The performance problem of the first solution could be worked around by creating an index on trunc(LAST_TRANSACTION_DATE) which could be used by that expression. But the expression LAST_TRANSACTION_DATE = '30-JUL-07' prevents an index usage as well because internally it's processed as to_char(LAST_TRANSACTION_DATE) = '30-JUL-07'
The important things to remember:
Never, ever rely on implicit data type conversion. It will give you problems at some point. Always compare the correct data types
Oracle DATE columns always contain a time which is part of the comparison rules.
You should not compare a date to a string directly. You rely on implicit conversions, the rules of which are difficult to remember.
Furthermore, your choice of date format is not optimal: years have four digits (Y2K bug?), and not all languages have the seventh month of the year named JUL. You should use something like YYYY/MM/DD.
Finally, dates in Oracle are points in time precise to the second. All dates have a time component, even if it is 00:00:00. When you use the = operator, Oracle will compare the date and time for dates.
Here's a test case reproducing the behaviour you described:
SQL> create table test_date (d date);
Table created
SQL> alter session set nls_date_format = 'DD-MON-RR';
Session altered
SQL> insert into test_date values
2 (to_date ('2007/07/30 11:50:00', 'yyyy/mm/dd hh24:mi:ss'));
1 row inserted
SQL> select * from test_date where d = '30-JUL-07';
D
-----------
SQL> select * from test_date where d like '30-JUL-07';
D
-----------
30/07/2007
When you use the = operator, Oracle will convert the constant string 30-JUL-07 to a date and compare the value with the column, like this:
SQL> select * from test_date where d = to_date('30-JUL-07', 'DD-MON-RR');
D
-----------
When you use the LIKE operator, Oracle will convert the column to a string and compare it to the right-hand side, which is equivalent to:
SQL> select * from test_date where to_char(d, 'DD-MON-RR') like '30-JUL-07';
D
-----------
30/07/2007
Always compare dates to dates and strings to strings. Related question:
How to correctly handle dates in queries constraints
The date field is not a string. Internally an implicit conversion is made to a string when you use =, which does not match anything because your string does not have the required amount of precision.
I'd have a guess that the LIKE statement behaves somewhat differently with a date field, causing implicit wildcards to be used in the comparison that eliminates the requirement for any precision. Essentially, your LIKE works like this:
SELECT ACCOUNT.ACCOUNT_ID, ACCOUNT.LAST_TRANSACTION_DATE
FROM ACCOUNT
WHERE ACCOUNT.LAST_TRANSACTION_DATE BETWEEN DATE('30-JUL-07 00:00:00.00000+00:00') AND DATE('30-JUL-07 23:59:59.99999+00:00');