PLSQL archiving LONG datatype, error: - sql

Im using Oracle 11g, attempting to move anything older than 90days to the History table using PL/SQL..BUT i have one of the columns using datatype of LONG. So i have found the SQL that i thought should work but it gives errors:
BEGIN
FOR ROW IN
(SELECT MESSSAGE_KEY,
DISTRIBUTION_ID,
MESSAGE,
SYSTEM_NAME,
MESSAGE_TYPE,
MESSAGE_NAME,
MESSAGE_STATUS,
LATEST_INBOUND,
CREATETS,
MODIFYTS,
CREATEUSERID,
MODIFYUSERID,
CREATEPROGID,
MODIFYPROGID,
LOCKID,
ENTITY_KEY,
ENTITY_NAME,
ENTITY_VALUE
FROM NWCG_INBOUND_MESSAGE
WHERE TO_CHAR (createts, 'YYYYMMDD') >= TO_CHAR ((sysdate-90), 'YYYYMMDD')
)
LOOP
INSERT INTO NWCG_INBOUND_MESSAGE_H
VALUES (
ROW.MESSSAGE_KEY,
ROW.DISTRIBUTION_ID,
ROW.MESSAGE,
ROW.SYSTEM_NAME,
ROW.MESSAGE_TYPE,
ROW.MESSAGE_NAME,
ROW.MESSAGE_STATUS,
ROW.LATEST_INBOUND,
ROW.CREATETS,
ROW.MODIFYTS,
ROW.CREATEUSERID,
ROW.MODIFYUSERID,
ROW.CREATEPROGID,
ROW.MODIFYPROGID,
ROW.LOCKID,
ROW.ENTITY_KEY,
ROW.ENTITY_NAME,
ROW.ENTITY_VALUE
);
END LOOP;
END;
This is the error i am getting:
Error report:
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at line 2
06502. 00000 - "PL/SQL: numeric or value error%s"
*Cause:
*Action:
From my research it looks like this error has been about a lot, but i cant find any of peoples solutions to work.... any ideas?

The long datatype has been one of the reasons why I've always advised against storing documents or long string in an Oracle database. Without reverting to C and OCI, it is hard to use.
Now we have clob and blob which are reasonable usable in PL/SQL and SQL. But there are still many occurrences of the LONG datatype to be found of it, also in the Oracle data dictionary. Especially in XXX_VIEWS (user_views, all_views, dba_views) it is a real problem. Maybe the original developer should have named it UNUSABLE :-).
There is a workaround when the LONG contents are smaller than 32 KB; for full functionality I would recommend migrating to CLOB or using C. Good luck!
--
-- This sample code works when the long is smaller than 32 KB.
-- It is known to work on 9i, 10g, 11g r1, 11g r2, but it assumes
-- that a LONG smaller than 32 KB can be put in a PL/SQL variable.
-- And then cast.
--
-- You might want to add an exception handler to handle exceptions
-- when the size is larger than 32 KB. In this sample, this situation
-- can not occur; the where clause with text_length ensures that.
--
declare
l_text_as_long long;
l_text_as_clob clob;
l_text_length user_views.text_length%type;
begin
select viw.text
, viw.text_length
into l_text_as_long
, l_text_length
from user_views viw
where viw.view_name = upper(l_object_name)
and viw.text_length <= 32767 /* To fix a problem when accessing a view that is larger than 32K, we have this condition. */
;
l_text_as_clob := cast(l_text_as_long as clob);
... do something interesting ...
end;

Related

Why am I receiving PLS-00103 when attempting to create this simple function?

I am trying to create this function:
create or replace function g(sN int) return char(3) as
t char(3);
begin
select pt into t from (
select pTT as pt, pC
from ple
order by pC asc
) where sN <= pC and rownum <= 1;
return t;
end;
/
I receive this following errors:
LINE/COL ERROR
-------- -----------------------------------------------------------------
1/31 PLS-00103: Encountered the symbol "(" when expecting one of the
following:
; is authid as cluster order using external varying character
large deterministic parallel_enable pipelined aggregate
result_cache accessible
2/9 PLS-00103: Encountered the symbol "CHAR" when expecting one of
the following:
, from into bulk
The symbol "," was substituted for "CHAR" to continue.
LINE/COL ERROR
-------- -----------------------------------------------------------------
2/16 PLS-00103: Encountered the symbol ";" when expecting one of the
following:
. ( , * % & - + / at mod remainder rem <an identifier>
<a double-quoted delimited-identifier> <an exponent (**)> as
from into || multiset bulk
11/8 PLS-00103: Encountered the symbol "end-of-file" when expecting
one of the following:
end not pragma final instantiable order overriding static
member constructor map
My questions:
In general, why do these errors happen or signify?
More specifically, why am I receiving this error?
My research:
There are a number of questions involving PLS-00103 on SO, but none of them seem to fit my function.
Some problems that I have seen on SO that caused PLS-00103 are:
The accidental use of a reserved word, like max or min, as a variable name.
The incorrect use of looping structure keywords, like using EXIT LOOP to end a
loop instead END LOOP.
Incorrectly assigning a value to a variable, like x + 9 = x.
Of course, this isn't a comprehensive list of the problems I've indicated as PLS-00103, but I don't think my function applies to any of the ones I have seen.
Parameters can only specify the base type, not precision, scale, length etc.
return char(3)
should be
return char
or perhaps better,
return ple.ptt%type
btw char is almost never a good idea. It doesn't avoid some overhead of variable length strings as some people seem to think, and it doesn't ensure that values such as 3-letter ISO currency codes will have the expected number of letters. All it will do is add blank spaces to the end of non-null values, sometimes when you don't expect it to, leading to obscure bugs. It was added solely for ANSI compatibility reasons, and you are really not supposed to use it in developing new systems using Oracle.

Unable to remove carriage returns in a LONG data type column using REPLACE function

I am working on a LONG column in Oracle SQL Developer and this column contains carriage returns that need to be removed. The error I'm getting after using :
REPLACE ( col_name , CHR(13) , '' ) is :
ORA-00932: inconsistent datatypes: expected CHAR got LONG
00932. 00000 - "inconsistent datatypes: expected %s got %s"
Is there a workaround for this ?
Answers or suggestions will be much appreciated!
You will not be able to do almost anything with LONG data type columns. You should convert them to CLOB. You just found a reason why that is.
https://docs.oracle.com/cd/B28359_01/appdev.111/b28393/adlob_long_lob.htm
There is a to_lob() function to convert LONG to CLOB, but that can only be used in the select portion of an insert statement (that is, it can only be used to convert a LONG column to a CLOB column). After the conversion, you should have no problems using text functions on the resulting CLOB. You may also want to look at CLOB-specific functions in the DBMS_LOB package:
http://docs.oracle.com/cd/E11882_01/appdev.112/e40758/d_lob.htm#ARPLS600

How to visualize CLOB content - Oracle

I want to select and visualize the content of a column with CLOB datatype (>100 bytes).
select UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR(ds_cirurgia,1,4000))
from AVISO_CIRURGIA
where cd_paciente = 123456789;
But I get this error:
[SELECT - 0 row(s), 0.000 secs] [Error Code: 997, SQL State: 42000] ORA-00997: illegal use of LONG datatype
I used UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR()) in another column and it works.
What is wrong in this case?
You can just leave it with the call to DBMS_LOB.SUBSTR: it returns a varchar2:
select DBMS_LOB.SUBSTR(ds_cirurgia,1,4000)
from AVISO_CIRURGIA
where cd_paciente = 123456789
However, keep in mind that Oracle SQL is only capable of having a varchar2 with 4000 bytes, not 4000 characters. Your call can fail if the string contains Unicode characters.
Your column type is LONG not CLOB. Simple look up it in USER_TAB_COLUMNS.
Here are some workaround how to resolve it. I'd recoment to change the type to CLOB with CTAS.
create table t1 as
select ...
to_lob(c) c /* convert to CLOB */
from t;
After that you can simple cast to VARCHAR such as
cast (substr(col_name,1,4000) as varchar2(4000))
UPDATE
of course you may also use DBMS_LOB.SUBSTR
DBMS_LOB.SUBSTR(col_name,4000,1)
but please note the signature of this function: 2nd parameter is length, 3rd offset (not vice versa as in substr).

Trying to use a where statement in cursor creation (PL/SQL)

I'm trying to create a block that accepts input from a prompt and uses that input to filter the result set for the cursor. Keep in mind I'm a novice here so I maybe making a very routine mistake, and thank you for your help. My current code is below.
Set serveroutput on
DECLARE
ACCEPT a PROMPT “Please Enter a Date, eg. Format - 01 or 30"
datev char
datev := &a;
CURSOR cur_day_cursor IS
SELECT Arrival_Date Adate
FROM FLIGHT
WHERE TO_CHAR(Arrival_Date, ‘DD’) = datev;
cur_day_cursor_var cur_day_cursor%ROWTYPE;
BEGIN
OPEN Cur_day_cursor;
LOOP
Fetch Cur_day_cursor
INTO cur_day_cursor_var;
EXIT WHEN cur_day_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE (cur_day_cursor_var.Adate);
END LOOP;
IF cur_day_cursor%ISOPEN THEN
CLOSE cur_day_cursor;
END IF;
END;
The where statement is causing my errors, so I was thinking that I may have to let the cursor collect all the data and then filter it when displaying, but I'm not sure if I can even do that.
The error I keep receiving ERROR at line 9:-
ORA-06550: line 9, column 1:
PLS-00103: Encountered the symbol "WHERE" when expecting one of the following:
begin function pragma procedure subtype type
current cursor delete
exists prior
I don't know exactly why Oracle is reporting the error at the WHERE. Sometimes the parser gets pretty confused by bad syntax and doesn't point to the real problem. You have several syntax errors before the cursor definition.
ACCEPT is a SQLPlus command, not a PL/SQL statement. Move your ACCEPT line above the DECLARE.
Also, your variable declaration and initialization are incorrect. The assignment should be part of the declaration line; you need to provide a length for the CHAR datatype; and the substitution value should be in quotes to be treated as a string. A valid version of your lines would be:
datev char(2) := '&a';
I ran the same query as above, and got the results perfectly fine.
You have few syntax as well as logical error which I corrected in your query. The syntax error(s) are -
datev char
datev := &a;
You can't do such an initialization in PL/SQL. You probably have to complete it in a single line like below -
datev char := &a;
The logical mistake(s) are -
Why use a CHAR variable to store data when you know that the value being returned is NUMBER.
You expect numbers from 1-31; then why do you choose the default size of char which as 1. It will fail if you provide a 2-digit number
Even if you increase the size of CHAR to CHAR(2), you will not get results when the users enters a number like 1 or 01, because for character wise comparison, '1' != '1 '(Mark the extra space at the end, because of char(2)); and also '1' != '01'.
The only solution for above is to use a NUMBER datatype.
Now here I am posting my query which is similar to your query, with a change of column name and table name. Please replace with your required names and try -
(Take care not to execute the ACCEPT....) with the PL/SQL block. It should be done in the SQL prompt first and then the other DECLARE section should be run.
--ACCEPT a NUMBER PROMPT 'Please Enter a Date, eg. Format - 01 or 30 :'
--Run the above line first in SQL Prompt and then execute the rest as whole
DECLARE
datev NUMBER(2) := &a;
CURSOR cur_day_cursor IS
SELECT Ename, HireDate Adate
FROM Emp
WHERE TO_CHAR(HireDate, 'D') = datev;
cur_day_cursor_var cur_day_cursor%ROWTYPE;
BEGIN
OPEN Cur_day_cursor;
LOOP
Fetch Cur_day_cursor
INTO cur_day_cursor_var;
EXIT WHEN cur_day_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE (cur_day_cursor_var.Adate);
END LOOP;
IF cur_day_cursor%ISOPEN THEN
CLOSE cur_day_cursor;
END IF;
END;
/
It appears that the problem is that the single-quotes around ‘DD’ aren't single-quotes. It looks like the code was created in an editor which changes apostrophes into those special "look kind of like single quotes but aren't really" characters. Replace the original version of the WHERE clause with the following:
WHERE TO_CHAR(Arrival_Date, 'DD') = datev;
and I suspect you'll be fine.
And get yourself a good code editor. :-)

TO_CHAR(number) Function returns ORA-01722: invalid number

Query:
Select To_Number(qty) From my_table Where Id=12345;
Output:
ORA-01722: invalid number
01722. 00000 - "invalid number"
Query: Select qty From my_table Where Id=12345;
Output: 0.00080
Query:
Select To_Number(0.00080) From Dual;
Output:
0.00080 (no error)
This is a odd situation I am facing in Oracle. Can anybody suggest why it happens? The column qty is NUMBER type. Hence it is very hard to imagine that it contains invalid number, but it happened.
I want to clarify that it happened for the specific value in the column although we have thousands of records in the same column.
Added more: The same error appears if I use TO_CHAR(qty) function. The qty column is NUMBER type not VARCHAR2. In fact we are using SUM(qty) function which showed error. Hence I went for a dissection and found this row being the culprit.
I'm assuming that qty is defined as a varchar2 in my_table-- otherwise, there would be no purpose served by calling to_number. If that assumption is correct, I'll wager that there is some other row in the table where qty has non-numeric data in it.
SQL is a set-based language so Oracle (or any other database) is perfectly free to evaluate things in whatever order it sees fit. That means that Oracle is perfectly free to evaluate the to_number(qty) expression before applying the id=12345 predicate. If Oracle happens to encounter a row where the qty value cannot be converted to a number, it will throw an error.
It is also possible that there is some non-numeric data in the particular row where id = 12345 that happens not to be displaying (control characters for example). You can check that by running the query
SELECT dump(qty, 1016)
FROM my_table
WHERE id = 12345
(if you want decimal rather than hexadecimal, use 1010 as the second parameter to dump) and checking to see whether there is anything unexpected in the data.
The only way I can see you could get the results you've shown, given that qty really is a number field, is if it holds corrupt data (which is why there has been scepticism about that assumption). I'm also assuming your client is formatting the value with a leading zero, but is not forcing the trailing zero, which wouldn't normally appear; you can of course force it with to_char(.0008, '0.00000'), but you don't appear to be doing that; still, the leading zero makes me wonder.
Anyway, to demonstrate corruption you can force an invalid value into the field via PL/SQL - don't try this with real data or a table you care about:
create table t42(qty number);
table T42 created.
declare
n number;
begin
dbms_stats.convert_raw_value('bf0901', n);
insert into t42 (qty) values (n);
end;
/
anonymous block completed
select qty from t42;
QTY
----------
.00080
select to_number(qty) from t42;
Error starting at line : 12 in command -
select to_number(qty) from t42
Error report -
SQL Error: ORA-01722: invalid number
01722. 00000 - "invalid number"
Note the plain query shows the number as expected - though with a trailing zero, and no leading zero - and running it through to_number() throws ORA-01722. Apart from the leading zero, that is what you've shown.
It also fails with to_char(), as in your question title:
select to_char(qty) from t42;
Error starting at line : 13 in command -
select to_char(qty) from t42
Error report -
SQL Error: ORA-01722: invalid number
... which makes sense; your to_number() is doing an implicit conversion, so it's really to_number(to_char(qty)), and it's the implicit to_char() that actually generates the error, I think.
Your comments suggest you have a process that is loading and removing data. It would be interesting to see exactly what that is doing, and if it could be introducing corruption. This sort of effect can be achieved through OCI as the database will trust that the data it's passed is valid, as it does in the PL/SQL example above. There are bug reports suggesting imp can also cause corruption. So the details of your load process might be important, as might the exact database version and platform.
I encountered the nearly same problem. And I found the mysterious number behaved differently from the normal number after dump(). For example, assuming my qty=500 (datatype: number(30,2)) , then:
select dump(qty) from my_table where Id=12345;
Typ=2 Len=3: 194,6,1
select dump(500.00) from dual;
Typ=2 Len=2: 194,6
If we know how number datatype be stored (if not, plz visit http://translate.google.com/translate?langpair=zh-CN%7Cen&hl=zh-CN&ie=UTF8&u=http%3A//www.eygle.com/archives/2005/12/how_oracle_stor.html ) , we can find that there is a tailing zero (the last extra "1" in Typ=2 Len=3: 194,6,1) in the mysterious number.
So I made a trick to eliminate the tailing zero, and it works for the problem.
select dump(trunc(qty+0.001,2)) from my_table where Id=12345;
Typ=2 Len=2: 194,6
Hope someone to explain the deep mechanism.
try this:
Select To_Number(trim(qty)) From my_table Where Id=12345;