I have a statement:
SELECT ('"' || TO_DATE(substr(idate,7,4) || '/' || substr(idate,3,2) || '/' || substr(idate,5,2), 'YYYY/MM/DD') || '"')
FROM heal;
which outputs
"15/02/04"
"15/01/03"
"15/01/20"
"15/01/10"
But I've created a column from this query to populate it as a DATE (ALTER TABLE heal ADD (CDATE DATE);)
While inserting
INSERT INTO heal (cdate) VALUES
('"' || TO_DATE(substr(idate,7,4) || '/' || substr(idate,3,2) || '/' || substr(idate,5,2), 'YYYY/MM/DD') || '"');
I get Error: 00984. 00000 - "column not allowed here"
When leaving outside quotes I have the same. This is something with quotes I've read in many other duplicated threads but still don't know how to quote it. Any he;p?
'idate' column as VARCHAR2(50):
b'02042015'
b'01032015'
b'01202015'
b'01102015'
I don't know why you need to make things so complicated:
UPDATE heal
SET cdate = TO_DATE(SUBSTR(idate, 3, 8), 'DDMMYYYY');
You don't need to use all that string manipulation. Just call TO_DATE once with the proper format mask.
You rather want an UPDATE, not an INSERT.
UPDATE heal
SET cdate = to_date(substr(idate, 7, 4) || '/' || substr(idate, 3, 2) || '/' || substr(idate, 5, 2), 'YYYY/MM/DD');
Here is one way to do this. I show a full demo, beginning with the creation of the table, populating the data (with NULL in the CDATE column), then the UPDATE statement. Note the use of "boilerplate text" in the format model to TO_DATE, and the use of q-quoting syntax to define strings that include single-quotes as literal characters.
In the final output, CDATE uses my current session's NLS_DATE_FORMAT parameter; the dates may look different on your system.
create table heal (idate varchar2(50), cdate date);
insert into heal (idate)
select q'[b'02042015']' from dual union all
select q'[b'01032015']' from dual union all
select q'[b'01202015']' from dual union all
select q'[b'01102015']' from dual;
select * from heal;
IDATE CDATE
------------------------------ --------------------------
b'02042015'
b'01032015'
b'01202015'
b'01102015'
update heal
set cdate = to_date(idate, q'["b'"mmddyyyy"'"]');
4 rows updated.
select * from heal;
IDATE CDATE
------------------------------ -------------------
b'02042015' 2015/02/04 00:00:00
b'01032015' 2015/01/03 00:00:00
b'01202015' 2015/01/20 00:00:00
b'01102015' 2015/01/10 00:00:00
Related
I have a column in oracle database table which is Varchar2. In this column I am storing date line 29-1-2021 or 28-12-2020. I want to retrieve data from below query between two dates then I am getting error of Invalid month. How can I resolve this issue ?
SELECT Line_Stop_Id, Function_name, Product_family, line_description, Reason_Category, Reason_detail,
Product_item, product_description, request_raised_date, request_raised_time, cm.EMP_NAME as raised_by, Lse.User_Closer_Description,
Cm1.Emp_Name as Closer_User, Lse.User_Closer_Date, Lse.Final_Closer_Description, Lse.Final_Closer_Date, Lse.Final_Closer_Time,
Cm2.Emp_Name as Final_Closer, Lse.Resource_Effected ,
ROUND(24*(sysdate - to_date(Request_Raised_Date
||' '
||request_raised_time, 'DD-Mon-RR HH24:MI:SS'))) AS TAT
FROM Xx_Lsp_Linestoppage_Entry lse
Left join Emp_Master cm ON Lse.Raised_By = Cm.Emp_No
Left join Emp_Master cm1 ON Lse.Closer_User = Cm1.Emp_No
Left join Emp_Master cm2 ON Lse.Final_Closed_By = Cm2.Emp_No
where TO_DATE(Lse.Request_Raised_Date, 'DD-Mon-RR') Between TO_DATE('01-Jan-21', 'DD-Mon-RR') and TO_DATE('29-Jan-21', 'DD-Mon-RR');
You should check the validity of your date values stored as strings before a conversion and do a cleanup of them (of fix them).
This can be done via, for example, cursor in PL/SQL block (or wrapped in function to export query results or filter by its value):
declare
l_date date;
begin
for r in (
select distinct
request_raised_time
from Xx_Lsp_Linestoppage_Entry
/*To reduce rows in cursor*/
where not regexp_like('^\d{2}-\d{2}-\d{4}')
) loop
begin
l_date := to_date(r.q, 'dd-mm-yyyy');
exception
when others then dbms_output.put_line('Invalid date: ' || r.q);
end;
end loop;
end;
/
db<>fiddle here
Note, that you need to quote dashes inside format to make it exact, because Oracle treats unquoted dash as any symbol from quite wide set of delimiters. So it will process 01/12/2020 as date '2020-12-01', not as invalid date.
select to_date('01/12/2021', 'dd-mm-yyyy') as dt from dual;
DT
--------------------
2021-12-01T00:00:00Z
Elapsed: 00:00:00.002
1 rows selected.
select to_date('01-12-2021', 'dd-mm-yyyy') as dt from dual;
DT
--------------------
2021-12-01T00:00:00Z
Elapsed: 00:00:00.002
1 rows selected.
select to_date('01$12$2021', 'dd-mm-yyyy') as dt from dual;
DT
--------------------
2021-12-01T00:00:00Z
Elapsed: 00:00:00.002
1 rows selected.
You are storing the date in the format 29-1-2020 (dd-mm-yyyy) so use this format in the to_Date
replace
DD-Mon-RR
with
dd-mm-yyyy
Probably being the Lse.Request_Raised_Date field of type varchar2 it contains more information than you need for your query.
I think the best way is to select a string that only identifies the part necessary for the identification of the date using the function:
substr(string , string start from , string lenght )
This is an example:
select to_date(substr('29-01-2021 23:01:55',1,10),'DD-MM-YYYY') from dual;
TO_DATE (SU
----------
29-01-2021
instead of my string '29 -01-2021 23:01:55 ' enter field Lse.Request_Raised_Date
You can use on conversion error:
to_date(Request_Raised_Date || ' ' || request_raised_time
default null on conversion error, 'DD-Mon-YYYY HH24:MI:SS')
This returns NULL instead of an error.
Hopefully, this is a lesson on why you should not store date/time values as strings. You can actually look for the bad values using:
select Request_Raised_Date, request_raised_time
from Xx_Lsp_Linestoppage_Entry
where to_date(Request_Raised_Date || ' ' || request_raised_time
default null on conversion error, 'DD-Mon-YYYY HH24:MI:SS') is null and
Request_Raised_Date is not null
This may give you some ideas on how to fix the data.
I realize I could use a combination of to_char and to_date and what not as a work-around, but I'm trying to figure out why this doesn't work. I am using Oracle 12.1
select '2016-10-01'
from dual
union all
select to_char(2016)||'-10-01'
from dual;
Each side of the union produces identical output: 2016-10-01. If I then try to use the ANSI date syntax (as described here: http://blog.tanelpoder.com/2012/12/29/a-tip-for-lazy-oracle-users-type-less-with-ansi-date-and-timestamp-sql-syntax/ ), it only works on the first one, not the second one:
select date '2016-10-01'
from dual
This returns: 10/1/2016
But if I try this:
select date to_char(2016)||'-10-01'
from dual;
I get on:
ORA_00936 missing expression error.
I can code a work-around, but I'm stumped as to why one works and the other does not.
It won't work that way because DATE is not a function but a literal.
The terms literal and constant value are synonymous and refer to a fixed data value.
Date Literals
You can specify a DATE value as a string literal, or you can convert a character or numeric value to a date value with the TO_DATE function. DATE literals are the only case in which Oracle Database accepts a TO_DATE expression in place of a string literal.
You could use TO_DATE function.
select TO_DATE(to_char(2016)||'-10-01', 'YYYY-MM-DD')
from dual;
Rextester Demo
EDIT:
Using dynamic-SQL:
DECLARE
i DATE;
stmt VARCHAR2(100);
BEGIN
stmt := q'{SELECT DATE '}' || TO_CHAR(2016) || '-01-01' || q'{' FROM dual}';
EXECUTE IMMEDIATE stmt INTO i;
DBMS_OUTPUT.PUT_LINE('i =>' || i);
END;
I am building an Oracle APEX application in which journalists can bring in articles, which a director selects for a broadcast, along with a newsreader (who can read the articles if the broadcast is created). I am kind of stuck with the following:
I would like to create an Oracle SQL query which selects the first and last name of a record in the "user" table, when its availability (which is stored in another table, "Beschikbaarheid") meets the given circumstances (user begin time at broadcast day >= broadcast begin time AND user end time at broadcast day <= broadcast end time).
I myself have written the following query.
SELECT voornaam || ' ' || achternaam AS display_value, id AS return_value
FROM Gebruiker
WHERE id NOT IN (SELECT Nieuwslezerselectie.nieuwslezerid FROM Nieuwslezerselectie
WHERE -- other conditions
AND id IN (SELECT gebruikerid
FROM Beschikbaarheid
WHERE (dag = to_char(to_date(:P91_DATUM,'DD-MON-YYYY'),'Day'))
AND (to_date(:P91_BEGINTIJD,'HH24:MI') >= to_date(begintijd,'HH24:MI'))
AND (to_date(:P91_EINDTIJD,'HH24:MI') <= to_date(eindtijd,'HH24:MI'))
);
(Excuse me if you are having trouble reading this, I use Dutch naming. Feel free to ask if something is unclear.)
However, the APEX select list to which this query is linked is not showing anything if the newsreader is available at the time of the broadcast. I think the problem is "Begintijd" and "Eindtijd" are stored as time stamps, as the values should be date-independent (which time stamps are not), but I have no clue how to store them otherwise. As a varchar maybe?
I sincerely hope you have any ideas. Thank you in advance!
Luc
update 1
With help I have rewritten the query, it now looks like this:
AND id IN (SELECT gebruikerid
FROM Beschikbaarheid
WHERE (dag = to_char(to_date(:P91_DATUM,'DD-MON-YYYY'),'Day','NLS_DATE_LANGUAGE=Dutch'))
AND (
to_date('01-01-2000' || ' ' || to_char(to_timestamp(:P91_BEGINTIJD),'HH24:MI'),'DD-MM-YYYY HH24:MI')
BETWEEN
to_date('01-01-2000' || ' ' || to_char(begintijd,'HH24:MI'),'DD-MM-YYYY HH24:MI')
AND
to_date('01-01-2000' || ' ' || to_char(eindtijd,'HH24:MI'),'DD-MM-YYYY HH24:MI')
)
AND (
to_date('01-01-2000' || ' ' || to_char(to_timestamp(:P91_EINDTIJD),'HH24:MI'),'DD-MM-YYYY HH24:MI')
BETWEEN
to_date('01-01-2000' || ' ' || to_char(begintijd,'HH24:MI'),'DD-MM-YYYY HH24:MI')
AND
to_date('01-01-2000' || ' ' || to_char(eindtijd,'HH24:MI'),'DD-MM-YYYY HH24:MI')
)
);
However, I am now getting the ORA-01840: input value not long enough for date format error when trying to access the page. I haven't discovered what causes that error yet. Does anyone have any clues?
update 2
Now I am confused. It turned out I didn't need to_char etc. for my page variables, so I removed those (to_char etc.). Now I am normally send to the correct page, but the last value I entered in the "set these items / with these values" text fields on the previous page, isn't send. This is what I have in these text fields right now:
In this image, P85_BEGINTIJD isn't send. I also switched the values around, but that didn't make a difference. Is there a limit to the amount of values you can send with a request, or something?
Do not use timestamps. se a date field, which includes date and time,
more info about date fields in oracle:
Oracle Data types, see paragraph Overview of DATE Datatype
If I got it right you have two columns with data type TIMESTAMP and you need to constraint it with a parameter, but using only the hour an minute part of it.
The simplest possible way to do it is use a string parameter in format HH:MI
select begintijd, to_char(begintijd,'HH24:MI') begintijd_hhmi,
eindtijd, to_char(eindtijd,'HH24:MI') eindtijd_hhmi from tst
where '22:00' between to_char(begintijd,'HH24:MI') and to_char(eindtijd,'HH24:MI')
;
Note that you use to_char with the date mask HH24:MI to get rid of the not relevant part of the date/time.
A probable better and more flexible way is to use INTERVALs.
with t2 as (
select
begintijd, begintijd - trunc(begintijd) begintijd_hhmi,
eindtijd, eindtijd - trunc(eindtijd) eindtijd_hhmi from tst)
select * from t2
where INTERVAL '22:00' HOUR TO MINUTE between begintijd_hhmi and eindtijd_hhmi
;
You use the difference of the timestamp and the truncated timestamp to calculate the interval (of hour and minutes). Note though, that if the timestamp can contain seconds or fractions of it, you may need to trim them out, e.g. with
NumToDsInterVal(60*extract(hour from begintijd)+extract(minute from begintijd),'MINUTE') begintijd_hhmi
Okay, so eventually, I was able to solve it. In my last update, the only lasting problem was that some variables weren't send to the next page. I wasn't able to find the root cause of the problem, so I did a workaround.
The only variable that was sent normally to the next page is P91_UITZENDING (the PK of Uitzending). Luckily, the other variables I needed (begintijd, eindtijd and datum) are attributes of Uitzending so I was able to derive them with statements like this in the source of the corresponding page item:
SELECT to_char(begintijd,'HH24:MI')
-- replace with eindtijd for eindtijd, and for date: to_char(datum,'DD-MON-YYYY')
FROM Uitzending
WHERE id = :P91_UITZENDING
And the final SQL query for the select box:
SELECT voornaam || ' ' || achternaam AS display_value, id AS return_value
FROM Gebruiker
WHERE -- Other statements
AND id IN (SELECT gebruikerid
FROM Beschikbaarheid
WHERE (dag = to_char(to_date(:P91_DATUM,'DD-MON-YYYY'),'fmDay','NLS_DATE_LANGUAGE=Dutch'))
AND (
to_date('01-01-2000' || :P91_BEGINTIJD,'DD-MM-YYYY HH24:MI')
BETWEEN
to_date('01-01-2000' || to_char(begintijd,'HH24:MI'),'DD-MM-YYYY HH24:MI')
AND
to_date('01-01-2000' || to_char(eindtijd,'HH24:MI'),'DD-MM-YYYY HH24:MI')
)
AND (
to_date('01-01-2000' || :P91_EINDTIJD,'DD-MM-YYYY HH24:MI')
BETWEEN
to_date('01-01-2000' || to_char(begintijd,'HH24:MI'),'DD-MM-YYYY HH24:MI')
AND
to_date('01-01-2000' || to_char(eindtijd,'HH24:MI'),'DD-MM-YYYY HH24:MI')
)
);
I still don't know why begintijd, eindtijd and datum weren't send the normal way, but at least it is working now.
Thank you all for your thinking and help!
I have function which returns a list of comma seperated dates(e.g. 'Dec 24, 2011','Dec 26, 2011','Dec 18, 2011','Dec 27, 2011'.
I am receiving this as a single string.
I want to use this string to build a select query where I want to use the string in the IN clause.
e.g.
select *
from wfdisplaymgmt
where programstartdate IN(TO_DATE('Dec 26, 2011','MON dd, yyyy'))
Since I am getting a multiple dates I would like to use all the dates in my statement.how can I write the sql query which inlcudes multiple dates.Please help.
Update:
One more thing is I have window with a textbox and a button on clicking the button a sql query is executed.The query returns a distinct number of column values which has an option of selecting each of those values.when the user selects the required values ,the values are copied to the text box(e.g.'Dec 24, 2011','Dec 26, 2011','Dec 18, 2011','Dec 27, 2011' if I have selected four dates).Now the String I want to use this string in a sql statement where I select all the columns of the table based on the selected dates found in the string i.e.values found in the text box.
'Mon DD,YYYY' is the date format returned in the string.
I want a query similar to
select *
from wfdisplaymgmt
where programstartdate IN(the date values coming from the text box)
how do I do this?
Change your PLSQL function to return a user-defined data type TABLE OF DATE (or TIMESTAMP) and use IN to match values.
Note you will probably need to TRUNC the date values in order to match them. Noon != Midnight!
The following code illustrates the approach.
WHENEVER SQLERROR EXIT FAIL ROLLBACK
set echo on
COLUMN programstartdate FORMAT A45
column column_value format a45
set serveroutput on
<<REINITIALIZE>>
BEGIN
FOR DOIT IN (SELECT 'DROP TABLE ' || TABLE_NAME AS CMD FROM USER_TABLES WHERE TABLE_NAME = 'WFDISPLAYMGMT')
LOOP
EXECUTE IMMEDIATE DOIT.CMD;
DBMS_OUTPUT.PUT_LINE ('Dropped test table via command: ' || doit.CMD);
end loop;
dbms_random.seed('This doesn''t quite feel random until I add the microseconds ' || to_char (systimestamp, 'D FF9'));
END REINITIALIZE;
/
CREATE OR REPLACE TYPE DATELIST AS TABLE OF date;
/
show errors type datelist
CREATE OR REPLACE FUNCTION GETDATES (HOWMANY IN NUMBER) RETURN DATELIST
IS
TO_RETURN DATELIST := datelist();
BEGIN
for stepback in 1 .. howmany
loop
to_return.extend();
TO_RETURN(stepback) := trunc(sysdate - stepback);
end loop;
RETURN TO_RETURN;
END GETDATES;
/
show errors function getdates;
select * from table(cast (getdates (7) as datelist));
create table WFDISPLAYMGMT
as
select
TRUNC(dbms_random.value (50, 10000)) as bogus_id,
column_value as programstartdate
from (select rownum as row_no, column_value from table(cast (getdates (30) as datelist)))
where abs (mod (row_no, 3)) = 1
;
commit;
select count (*) as generated_rows from WFDISPLAYMGMT;
select *
from WFDISPLAYMGMT
where programstartdate in (select * from table (cast (getdates (15) as datelist)));
Here's a slightly convoluted way to do this in SQL only. The below is a sample you can run immediately in your instance to check it out:
select to_date(replace(VAL, '''', ''), 'Mon dd, yyyy') as NEWDATE
from (with TST1 as
(select length(DTXT) - length(translate(DTXT, REPLVAL || VALSEP, REPLVAL)) + 1 as NUMVAL
,VALSEP
,DTXT || VALSEP as DTXT
from (select replace('''Dec 24, 2011'',''Dec 26, 2011'',''Dec 18, 2011'',''Dec 27, 2011'''
,''','''
,'''|''')
as DTXT
,'|' as VALSEP
,chr(0) as REPLVAL
from dual))
select substr(TST1.DTXT
,decode(rownum, 1, 1, instr(TST1.DTXT, VALSEP, 1, rownum - 1) + length(VALSEP))
, instr(TST1.DTXT, VALSEP, 1, rownum)
- decode(rownum, 1, 0, instr(TST1.DTXT, VALSEP, 1, rownum - 1))
- 1)
as VAL
from TST1
connect by level <= TST1.NUMVAL)
What it does is take your comma-separated dates and converts them into individual records that can then be cast to date type. In your scenario you can replace the sub-query that selects from dual with your function, e.g.:
select *
from wfdisplaymgmt
where programstartdate IN (
select to_date(replace(VAL, '''', ''), 'Mon dd, yyyy') as NEWDATE
...
select replace(myfunctioncall()
,''','''
,'''|''')
as DTXT
,'|' as VALSEP
,chr(0) as REPLVAL
from dual
...
What I've done here is replace the comma separators with pipe separators as you have a comma appearing in the date format. Also, I have appended the pipe separator to the end of the text so that the last value is included. If you need further details on what each bit does then add a comment.
you can use the EXECUTE() function to execute a string as a sql statement, that would work, or else you just can split the string of dates up into a table variable and then use in on the table variable. Both work, I think the table variable is probably a better solution.
Assuming oracle and I'm rusty at best for that techology
select *
from wfdisplaymgmt
where instr(your_function_that_delivers_dates()
, TO_CHAR(programstartdate,'MON DD, YYYY')) > 0
Don't expect blasting performance on large tables because the queryplan is not going to use any index, instead it will do a full-table scan
Based on info found here
Consider creating a new function (or replacing the old) that returns you a table (array) of data instead of a csv list in single string. It will be much easier to actually use the function in a meaningful way:
-- Create types
CREATE TYPE t_tf_row AS OBJECT (
id NUMBER,
dte date
);
/
CREATE TYPE t_tf_tab IS TABLE OF t_tf_row;
/
-- Build the table function itself.
CREATE OR REPLACE FUNCTION get_tab_tf (p_rows IN NUMBER) RETURN t_tf_tab AS
l_tab t_tf_tab := t_tf_tab();
l_dte date;
BEGIN
-- create rows
FOR i IN 1 .. p_rows LOOP
l_dte := sysdate - i;
l_tab.extend;
l_tab(l_tab.last) := t_tf_row(i, l_dte);
END LOOP;
RETURN l_tab;
END;
/
-- test new function, selecting 20 dates
select * from MY_TABLE
where MY_DATE in (select dte from table(get_tab_tf(20)));
Of course, in your version of the function create the dates the way you need them. Also note that you could do a pipelined version as well, but I assume the list of dates is reasonable in length.
I am trying to create a trigger in Oracle that compares two dates and then deletes records if the difference of the two dates falls below a certain value. I have a full date value with the format 'DD-MON-YYYY HH24MI' and then for the second date value, I want to concatenate a 'DD-MON-YYYY' value with a 'HH24MI' value.
The problem I am getting is that when I try to concat the date and time value together using to_char, and then using to_date on that returned value, it gives me a ORA-01481 invalid number format error. The relevant lines from the trigger itself are below. If anyone can help me out with this, it would be greatly appreciated!
CREATE OR REPLACE TRIGGER dateTrig
...
DECLARE
day date;
ftime date;
CURSOR c_table1 IS SELECT ...;
BEGIN
FOR entry IN c_table1 LOOP
day := to_date(entry.fdate);
ftime := to_date(to_char(day, 'DD-MON-YYYY') || ' ' || to_char(entry.dtime, 'HH24MI'), 'DD-MON-YYYY HH24MI'); -- this is the line that is causing the error
dbms_output.put_line(day || ', ' || ftime);
END LOOP;
END;
/
Since DTIME is not a date type, you cannot use TO_CHAR with a date format. If it's zero padded to a length of 4 characters, you can simplify it like this:
ftime := to_date(to_char(day, 'DD-MON-YYYY') || ' ' || entry.dtime, 'DD-MON-YYYY HH24MI');
I think your best to avoid using to_char's if you can and try to stick with functions that return values in their native date formats, this way you may also not need to run a to_date command on your string, you may have some success with the following or a close relation to it:
ftime := Trunc(Sysdate) || ' ' || Extract(Hour From entry.dtime) || ':' Extract(Minute From entry.dtime)
Best of luck