convert varchar field data in date format in oracle - sql

I have table test column has cretaed_dt and id.Both are varchar 2 type.
desc test
ID Varchar2(30)
Created_Dt varchar2(30)
select * from test
ID created_dt
1 2014-07-22-12.23.49.832868
2 2014-08-04-19.40.11.787317
3 2014-06-15-19.40.11.787317
I need to pick the data between 21st July to 5th aug 2014.Idealy ID 1 and 2 need to pick.
I am not able to do this because created date column is in varchar2.
Please assist.

Although your data is stored as varchar2(), you can still use it. Happily the strings are in the right format for comparison operations. So:
where created_dte >= '2014-07-21' and created_dte < '2014-08-05'
You can convert the varchar2() to a date using to_date(). However, just using the string as is allows Oracle to take advantage of an index on the column.
Although you can do what you want, you should store date/times in native date format in the database. Oracle has a wealth of date-related functions that are then accessible.

Use this:
with t as (
select '1' id, '2014-07-22-12.23.49.832868' created_dt from dual union all
select '2' id, '2014-08-04-19.40.11.787317' created_dt from dual union all
select '3' id, '2014-06-15-19.40.11.787317' created_dt from dual
)
select *
from t
where to_timestamp(created_dt, 'yyyy-MM-dd-HH24.MI.SS.FF') between to_date('21 jul 2014', 'DD mon YYYY') and to_date('5 aug 2014', 'DD mon YYYY')

Related

Count distinct values from subquery using TO_CHAR(date,'dd.mm.yyyy hh24') hourly

I try to get the distinct values from one column for a day and group the sum using different column by hour using to_char.
For Example:
select to_char(date,'dd.mm.yyyy hh24'),count(*) from select distinct(name) from table_name
where date > to_date(some_date_format)
and date < to_date(some_date_format)
group by to_char(date,'dd.mm.yyyy hh24')
order by 1
Result Example:
01.01.01 01 233
01.01.01 02 233
01.01.01 03 233
01.01.01 04 233
01.01.01 05 233
I get the result hourly but without the distinct column 'name' values from the subquery.
Can somebody explain me where is my mistake.
Thank you!
Is this what you're looking for ?
CREATE TABLE table_name (name, my_date) AS
(
SELECT 'foo', TO_DATE('01-JAN-2021 14:30','DD-MON-YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 'bar', TO_DATE('01-JAN-2021 14:30','DD-MON-YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 'bar', TO_DATE('01-JAN-2021 14:30','DD-MON-YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 'foo', TO_DATE('01-JAN-2021 15:35','DD-MON-YYYY HH24:MI') FROM DUAL
);
table created
SELECT TO_CHAR(my_date, 'DD-MON-YYYY HH24') as "date",
name,
count(*)
FROM table_name
GROUP BY TO_CHAR(my_date, 'DD-MON-YYYY HH24'),
name;
date NAM COUNT(*)
----------------------- --- ----------
01-JAN-2021 15 foo 1
01-JAN-2021 14 foo 1
01-JAN-2021 14 bar 2
Your query is returning the number of distinct names (it's using the COUNT command), not the list of names, as you may want it to do.
Because you're grouping the results by timestamp, you'll have at maximum 1 row for each timestamp, so you need to show the distinct names in a single row.
I suggest you to use Oracle's LISTAGG command to do that -- see the documentation here https://docs.oracle.com/cd/E11882_01/server.112/e41084/functions089.htm#SQLRF30030
Grouping data from different rows into a single row is not part of the standard SQL specification, so each SQL manufacturer will have its own implementation of this function (or even it won't have, sometimes).
Also, keep in mind that, because this list can grow, it can end up with some performance issues (some manufacturers will need you to set some buffer parameters in order to accomodate this calculated data into a single column).
Thanks for help.
I found my mistake:
select
to_char(date, 'dd.mm.yyyy hh24'), count(distinct name)
from
table_name
where
date > to_date(some_date_format)
and date < to_date(some_date_format)
group by
to_char(date, 'dd.mm.yyyy hh24')
order by 1
When I use count(distinct name), it counts all distinct name values hourly.
I was doing it wrong in the beginning using subquery.

BETWEEN Two Dates is Returning Rows of the Same Two Dates instead of the Ones Between

I'm trying to select rows that are between two specific dates, but I'm getting the rows that are of the same dates specified in BETWEEN instead. I tried using operators > and <, but nothing seems to work. Does it have to do with the date format?
SELECT r.RESERVATION_ID, a.AGENT_ID, a.AGENT_FNAME AS AGENT_NAME, t.TRIP_ID,
s.RESERVATION_STATUS
FROM RESERVATION r
INNER JOIN AGENT a
ON
a.AGENT_ID=r.AGENT_ID
INNER JOIN TOURTRIP_RESERVATION t
ON
r.RESERVATION_ID=t.RESERVATION_ID
INNER JOIN RESERVATION_STATUS s
ON
r.RESERVATION_STATUSID=s.RESERVATION_STATUSID
WHERE r.AGENT_ID IS NOT NULL
AND r.RESERVATION_DATE BETWEEN '15-MAR-20' AND '26-MAY-20'
AND r.RESERVATION_STATUSID=100;
I used to_date('03.06.2020','DD.MM.YYYY') format to update the data in the reservation_id column. However, when I use
and RESERVATION_DATE > to_date('15.03.2020','DD.MM.YYYY')
and RESERVATION_DATE < to_date('26.05.2020','DD.MM.YYYY')
it's returning nothing
This is the reservation table
The condition between includes the start and the end.
You can use the operators > and < to exclude it.
Your example simplified:
create table RESERVATION (
RESERVATION_ID number
,RESERVATION_DATE date)
Data:
insert into RESERVATION values (1, to_date('01.06.2020','DD.MM.YYYY'));
insert into RESERVATION values (2, to_date('02.06.2020','DD.MM.YYYY'));
insert into RESERVATION values (3, to_date('03.06.2020','DD.MM.YYYY'));
Query A)
select RESERVATION_ID
from RESERVATION
where RESERVATION_DATE between to_date('01.06.2020','DD.MM.YYYY')
and to_date('03.06.2020','DD.MM.YYYY')
will return:
1
2
3
The Query B)
select RESERVATION_ID
from RESERVATION
where RESERVATION_DATE > to_date('01.06.2020','DD.MM.YYYY')
and RESERVATION_DATE < to_date('03.06.2020','DD.MM.YYYY')
will return
2
I assume that RESERVATION_DATE is a date. Use always explicit datatype conversion.
I changed the date format, try this and tell me if you have other result.
SELECT r.RESERVATION_ID, a.AGENT_ID, a.AGENT_FNAME AS AGENT_NAME, t.TRIP_ID,
s.RESERVATION_STATUS
FROM RESERVATION r
INNER JOIN AGENT a
ON
a.AGENT_ID=r.AGENT_ID
INNER JOIN TOURTRIP_RESERVATION t
ON
r.RESERVATION_ID=t.RESERVATION_ID
INNER JOIN RESERVATION_STATUS s
ON
r.RESERVATION_STATUSID=s.RESERVATION_STATUSID
WHERE r.AGENT_ID IS NOT NULL
AND r.RESERVATION_DATE BETWEEN '2020-03-15' AND '2020-05-26'
AND r.RESERVATION_STATUSID=100;
If RESERVATION_DATE column's datatype is DATE, don't compare it to strings, because '15-MAR-20' is a string. Oracle will try to implicitly convert it to a valid date value; sometimes it'll succeed, sometimes it'll return false value (as its NLS settings differ from what you provided), and sometimes it'll fail and raise an error.
These two:
date '2020-03-15'
to_date('15.03.2020', 'dd.mm.yyyy')
on the other hand, are dates.
BETWEEN is inclusive and will return both limits, if they exist:
AND r.RESERVATION_DATE BETWEEN date '2020-03-15' and date '2020-05-26'
If you want to exclude those limits, then
AND r.RESERVATION_DATE > date '2020-03-15'
AND r.RESERVATION_DATE < date '2020-05-26'
But, if RESERVATION_DATE is a VARCHAR2 column, you're doing a big mistake. Never store dates as strings. If you can't afford modifying datatype, then you'll have to convert it to date:
and to_date(r.reservation_date, 'dd-mon-yy') between date '2020-03-15'
and date '2020-05-26'
This will work as long as there aren't any invalid values in that column. Because, as it is a string, you can put something like 15-AA-2F which certainly isn't a date, but can be stored into such a column. In that case, query will fail and you'll have to fix data.
Comment you posted says that you tried TO_DATE('26-MAY-20'). That's not enough - you should provide format mask as that can be
26th of May 2020
20th of May 2026
and it depends on NLS settings. Furthermore, it'll fail in my database:
Because NLS settings are different:
SQL> select to_date('26-may-20') from dual;
select to_date('26-may-20') from dual
*
ERROR at line 1:
ORA-01858: a non-numeric character was found where a numeric was expected
Because we don't have "may" in Croatia:
SQL> select to_date('26-may-20', 'dd-mon-yy') from dual;
select to_date('26-may-20', 'dd-mon-yy') from dual
*
ERROR at line 1:
ORA-01843: not a valid month
But this works, as I told Oracle what I want:
SQL> select to_date('26-may-20', 'dd-mon-yy', 'nls_date_language = english') from dual;
TO_DATE('26-MAY-20'
-------------------
26.05.2020 00:00:00
Even better, use digits only or date literal (which is always a date 'yyyy-mm-dd'):
SQL> select to_date('26.05.2020', 'dd.mm.yyyy') d1,
2 date '2020-05-26' d2
3 from dual;
D1 D2
------------------- -------------------
26.05.2020 00:00:00 26.05.2020 00:00:00
SQL>
Based on sample data you provided, presuming that reservation_date column's datatype is date:
setting environment first
sample data is from line #1 - 9
query you need begins at line #10
Here you go:
SQL> alter session set nls_date_language = 'english';
Session altered.
SQL> alter session set nls_Date_format = 'dd-mon-yy';
Session altered.
SQL> with reservation (reservation_id, reservation_date, agent_id) as
2 (select 8576, date '2020-03-15', 222 from dual union all
3 select 7325, date '2020-05-26', 333 from dual union all
4 select 3186, date '2020-04-23', 111 from dual union all
5 select 8000, date '2020-04-05', 555 from dual union all
6 select 4120, date '2020-01-03', null from dual union all
7 select 1546, date '2020-02-15', null from dual union all
8 select 1007, date '2020-05-06', null from dual
9 )
10 select *
11 from reservation
12 where reservation_date between date '2020-03-15'
13 and date '2020-05-26'
14 order by reservation_date;
RESERVATION_ID RESERVATI AGENT_ID
-------------- --------- ----------
8576 15-mar-20 222
8000 05-apr-20 555
3186 23-apr-20 111
1007 06-may-20
7325 26-may-20 333
SQL>

UPDATE month and year to current but leave day

I have situation in Oracle DB where I need to UPDATE every month some dates in table following this condition:
1) If date in table like '03.06.2017' UPDATE to '03.11.2017'
2) If date in table like '29.06.2016' UPDATE to '29.11.2017'
2) If date in table like '15.02.2016' UPDATE to '15.11.2017'
So basically always UPDATE part of date(month, year) to current month/year but always leave day as it is.
Edit:
It will be all months from 1-12 not only June. I need to do something like this... UPDATE table SET date = xx.(month from sysdate).(year from sysdate) WHERE... xx (day) leave as it is in DB.
Br.
You can use MONTHS_BETWEEN to determine how many months you need to add and then use the ADD_MONTHS function:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE dates ( value ) AS
SELECT DATE '2017-06-03' FROM DUAL UNION ALL
SELECT DATE '2016-06-29' FROM DUAL UNION ALL
SELECT DATE '2016-02-15' FROM DUAL UNION ALL
SELECT DATE '2016-03-31' FROM DUAL;
Update:
UPDATE dates
SET value = ADD_MONTHS(
value,
CEIL( MONTHS_BETWEEN( TRUNC( SYSDATE, 'MM' ), value ) )
);
Query 1:
SELECT * FROM dates
Results:
| VALUE |
|----------------------|
| 2017-11-03T00:00:00Z |
| 2017-11-29T00:00:00Z |
| 2017-11-15T00:00:00Z |
| 2017-11-30T00:00:00Z | -- There are not 31 days in November
Probably you want
update your_table
set this_date = add_months(this_date, 5)
where ...
This will add five months to the selected dates.
Your edited question says you want to update all the dates to the current month and year; you can automate it like this ...
update your_table
set this_date = add_months(this_date,
months_between(trunc(sysdate,'mm'), trunc(this_date, 'mm')))
-- or whatever filter you require
where this_date between trunc(sysdate, 'yyyy') and sysdate
/
Using month_between() guarantees that you won't get invalid dates such as '2017-11-31'. You say in a comment that all the dates will be < 05.mm.yyyy but your sample data disagrees. Personally I'd go with a solution that doesn't run the risk of data integrity issues, because the state of your data tomorrow may will be different from its state today.
Check out the LiveSQL demo.
I would start off with something like this to get my dates and then craft an update from it (substitute old_date with your date column and source_table with the table name):
select old_date, to_char(sysdate, 'YYYY-MM-') || to_char(old_date, 'DD') from source_table;

Oracle date extract and concatenate

I have to take a date (dd-mon-yyyy) and change the year based on a user input. How do I extract the day and month and add the year while keeping the format?
For example, it is currently 01-JAN-2015, and the user wants it to be 01-JAN-2016. I currently am doing:
SELECT EXTRACT(DAY FROM contract_year) || EXTRACT(MONTH FROM contract_year) || '2016'
FROM table
WHERE program = programid
And my output is 112016, but I want 01-JAN-2016. Any suggestions?
Try this
SELECT to_char(add_months('01-JAN-2015', 12*1),'dd-MON-yyyy') -- replace 1 with n where n = years
from dual
If you want to add use given year to current date/month, use this
with your_table as(
select '01-JAN-2015' as contract_year from dual
)
select to_date(substr(to_char(contract_year),1,7)||'2017','DD-MON-YYYY') from your_table
If your are not seeing output as required, it means that you have to change your client setting. Try running this in SQL Plus window.
Combine to_date and to_char:
SELECT to_date(to_char(contract_year,'dd-mm-') || '2016','dd-mm-yyyy')
FROM table
WHERE program = programid
It's not entirely clear to me whether contract_year is a date or a string.
If it's a date:
select to_char(contract_year, 'DD-MON-') || '2016'
from table
If it's a string in the format DD-MON-YYYY then:
select to_char(to_date(contract_year, 'DD-MON-YYYY'), 'DD-MON-') || '2016'
from table

Oracle order by date gives different results

Just curious as to why the below two queries would give different results, when the testdate column is of datatype DATE.
select testdate from <table> order by to_date(testdate) desc;
Returns
18-DEC-14
17-DEC-14
14-JUL-14
10-JUL-14
.
select testdate from <table> order by testdate desc;
Returns
13-NOV-13
18-DEC-14
17-DEC-14
14-JUL-14
Why would that November 2013 result appear at the top of the second results when as I say the coumn TESTDATE is of data tyle DATE and to_date() resolves the issueX?
Based on OP's reply via comments, the issue is:
SQL> WITH dates(dt) AS(
2 SELECT to_date('18-DEC-2014', 'DD-MON-RR') FROM dual UNION ALL
3 SELECT to_date('17-DEC-2014', 'DD-MON-RR') FROM dual UNION ALL
4 SELECT to_date('14-JUL-2014', 'DD-MON-RR') FROM dual UNION ALL
5 SELECT to_date('10-JUL-2014', 'DD-MON-RR') FROM dual UNION ALL
6 SELECT to_date('13-NOV-3013', 'DD-MON-RR') FROM dual
7 )
8 SELECT dt yy_date,
9 TO_CHAR(dt, 'DD-MON-YYYY') yyyy_date
10 FROM dates
11 ORDER BY dt DESC;
YY_DATE YYYY_DATE
--------- -----------
13-NOV-13 13-NOV-3013
18-DEC-14 18-DEC-2014
17-DEC-14 17-DEC-2014
14-JUL-14 14-JUL-2014
10-JUL-14 10-JUL-2014
SQL>
Th client is displaying the year as YY due to which year 3013 is displayed as 13 and along with other dates 2014, it looked as if 2013 is ordered before 2014 in descending order.
Use TO_CHAR to display the date in your desired format, and use TO_DATE to convert a literal into date.
On a side note,
Never use TO_DATE on a DATE, It will implicitly convert it into string and then back to date using locale-specific NLS format.
TO_DATE function expects string to convert it to date with a given format. Providing date column to to_date may result in unexpected behaviour even oracle does not complain about the given input.