ORA-12714: invalid national character set specified - oracle

I got a problem with oracle database ,i created a stored procedure and i wanted to pass an array of items' ids to this procedure to select the data according to array of items using "in" clause,the available solution to this as i found was to create a function and pass a string value with all item's ids seperated by a comma ,and this function will return a datatble with a row for each item id.this approach works fine when i try it in toad in a select statement,,but when i use it in the stored procedure i get a strange error
"ORA-12714: invalid national character set specified"
after searching about the reason of that error i found that it is a bug in that version of oracle according to this page and it was fixed in a 10.2.0.4 oracle patch and the exact reason is to declare a cursor for the function that returns a data table
As it is impossible to me to let the users who work on a live production environment to stop the servers to apply the update patch ,I was wondering if any Oracle expert can help me to declare a cursor and return that cursor instead of returning the table.
my Oracle function,Thanks in Advance
create or replace
FUNCTION SplitIDs(
v_List IN VARCHAR2)
RETURN RtnValue_Set PIPELINED
AS
SWV_List VARCHAR2(2000);
v_RtnValue Dt_RtnValue := Dt_RtnValue(NULL);
BEGIN
SWV_List := v_List;
WHILE (instr(SWV_List,',') > 0)
LOOP
FOR RetRow IN
(SELECT ltrim(rtrim(SUBSTR(SWV_List,1,instr(SWV_List,',') -1))) SelectedValue
FROM dual
)
LOOP
v_RtnValue.SelectedValue := RetRow.SelectedValue;
PIPE ROW(v_RtnValue);
END LOOP;
SWV_List := SUBSTR(SWV_List,instr(SWV_List,',')+LENGTH(','),LENGTH(SWV_List));
END LOOP;
FOR RetRow IN
(SELECT ltrim(rtrim(SWV_List)) SelectedValue FROM dual
)
LOOP
v_RtnValue.SelectedValue := RetRow.SelectedValue;
PIPE ROW(v_RtnValue);
END LOOP;
RETURN;
END;

Oracle says this about the error:
Error: ORA-12714 (ORA-12714)
Text: invalid national character set specified
Cause: Only UTF8 and AL16UTF16 are allowed to be used as the national character set
Action: Ensure that the specified national character set is valid
Check your NLS_NCHAR_CHARACTERSET which is set using:
select value from NLS_DATABASE_PARAMETERS where parameter = 'NLS_NCHAR_CHARACTERSET';
Try using NCHAR, NVARCHAR2 or NCLOB

Related

Creating Oracle PL/SQL Stored procedure

I'm trying to convert the SQL Query to Oracle PL/SQL stored procedure.
Here is the query:
select * from table1 where DATE = " + s1 + " and TYPE='" + ty + "' and NAME='"+nm+"' Order by TYPE DEsc;
Here is the Stored Procedure:
CREATE PROCEDURE procedure1
(
s1 IN DATE,
ty IN CHAR DEFAULT 2,
nm IN VARCHAR2 DEFAULT 64
)
IS
d table1.DATE%TYPE;
C table1.TYPE%TYPE;
S table1.NAME%TYPE;
CURSOR tb IS select DATE,TYPE,NAME INTO d,c,s from table1;
BEGIN
FOR i IN tb
LOOP
DBMS_OUTPUT.PUT_LINE('DATE' ||i.DATE);
DBMS_OUTPUT.PUT_LINE('TYPE' ||i.TYPE);
DBMS_OUTPUT.PUT_LINE('NAME' ||i.NAME);
END LOOP;
END procedure1;
I do not see any output after Executing Stored procedure. I'm not sure if I have created the stored procedure correctly.
"I do not see any output after Executing Stored procedure"
Your "output" is DBMS_OUTPUT which is for displaying text to a screen. However, by default it writes the text to a buffer, and we need to enable the output to see the contents of the buffer.
How to do this varies depending on which client you're using. In SQL*Plus it's
SQL> set serveroutput on
In an IDE like TOAD, PLSQL Developer or Oracle SQL Developer there's a separate DBMS_OUTPUT tab: click on the tab and enable output (there's a button) - or set Preferences to always have it on.
DBMS_OUTPUT is rarely a useful means for returning data in an actual application. The normal approach is to use a Ref Cursor, which maps to JDBC and ODBC ResultSet classes. Something like this:
CREATE OR REPLACE PROCEDURE procedure1
(
s1 IN DATE,
ty IN CHAR DEFAULT 2,
nm IN VARCHAR2 DEFAULT 64,
rc out sys_refcursor
)
IS
BEGIN
open rc for
select * from table1
where d = s1
and c = ty
and s = nm;
END procedure1;
/
Incidentally, your parameters are defined with string datatypes but the defaults are numeric values. Please don't get into bad habits. Strong datatyping is a key defence against data corruption and broken code, so always use the correct data type.
try this;
CREATE PROCEDURE PROCEDURE1 (
S1 IN DATE,
TY IN CHAR DEFAULT 2,
NM IN VARCHAR2 DEFAULT 64
)
IS
BEGIN
FOR I IN (SELECT DATE, TYPE, NAME FROM TABLE1)--Easier way to use cursor
LOOP
DBMS_OUTPUT.PUT_LINE ('DATE' || I.DATE);
DBMS_OUTPUT.PUT_LINE ('TYPE' || I.TYPE);
DBMS_OUTPUT.PUT_LINE ('NAME' || I.NAME);
END LOOP;
END PROCEDURE1;
by executing this you only created the procedure and stored it in db, you need to call it and turn on system output to see the output. like this:
set serveroutput on;
begin
PROCEDURE1(null, null, null);
end;
What environment are using to compile your code? You should certainly be seeing some immediate feedback.
Note that in most environments, though, you need to do a little more than you did before.
The final ";" in your code is part of PL/SQL. It does not trigger execution of your DDL. Generally you should do this:
CREATE OR REPLACE PROCEDURE myproc
IS
BEGIN
...
END myproc;
/
And that "/" will submit your statement for execution.

"Procedure successfully completed", but does not show the output, even when it should return values

I have created a stored procedure in SQL Developer (Oracle):
CREATE OR REPLACE Procedure SP_test
(Identificadores IN varchar,
separador IN varchar,
codigo IN char,
resultSet out sys_refcursor)
AS
BEGIN
open resultSet for
SELECT DISTINCT
(tb.CODIGO||separador||tb.NOMBRE) AS Campo
FROM TABLA tb
WHERE
tb.CODIGO = codigo
and concat(tb.IDENTIFICADOR,tb.TECLA) in (Identificadores);
-- and concat(tb.IDENTIFICADOR,tb.TECLA) in ('FR45');
END;
/
The problem arises when executing the stored procedure, since the result is: "procedure successfully completed", but does not show any data. In contrast, if you only change the WHERE clause in the Identifiers variable by its value (hardcode the value, as in the commented line), it does return all the rows that correspond. I do not understand xq if you pass the same value as parameter does not work. So I execute the proce:
set serveroutput on;
variable rs refcursor;
exec SP_test('FR45','|', '1',:rs);
print rs;
There is no error with any of the other parameters, and although I have tried sending only "FR45" as parameter Identifiers, the application could send a list of codes separated by "," (from there importing of using IN and not a simple EQUAL) . I've already tried using "instr ()" instead of IN and even creating views ... and nothing.
It's more than 4 days and I can not find a solution: (please .. any idea what I should do so that the procedure recognizes the Identifiers parameter in the IN clause and returns the column of data that I need? :(
PS I had the same procedure In SQL-Server and it worked perfect..

Formatting Date Error - Oracle 11g

Trying to write a SQL query to format a date output, but I am getting an error stating, 'a non-numeric character was found where a numeric is expected.'
Below is my SQL:
SELECT e.emp_num, emp_lname, emp_fname, sal_amount
FROM LGEMPLOYEE e
JOIN LGSALARY_HISTORY sh ON e.emp_num = sh.emp_num
WHERE sal_from = (SELECT MIN (to_date(sal_from,'dd-mon-yy'))
FROM LGSALARY_HISTORY sh
WHERE sh.emp_num = e.emp_num)
ORDER BY e.emp_num;
Can anyone help to resolve this issue?
Try to replace
MIN (to_date(sal_from,'dd-mon-yy'))
with
TO_CHAR(MIN (to_date(sal_from,'dd-mon-yy')), 'dd-mon-yy')
You're trying to compare VARCHAR2 with a DATE. Oracle uses an implicit types conversation using the following rule:
When comparing a character value with a DATE value, Oracle converts
the character data to DATE.
Just an assumption: Oracle is trying to convert sal_from to a DATE using default NLS settings (session or database) and apparently fails (because the default date format is 'dd-mm-yy' for example)
This is why it's never a good idea to store date values in a varchar2 column. There is at least one row in your table where the character string in sal_from isn't in the format you expect. That's causing the to_date call to throw an error.
One way of isolating the problematic rows would be something like
CREATE OR REPLACE FUNCTION is_valid( p_str IN VARCHAR2, p_mask IN VARCHAR2 )
RETURN VARCHAR2
IS
l_date DATE;
BEGIN
l_date := to_date( p_str, p_mask );
RETURN 'Y';
EXCEPTION
WHEN others THEN
RETURN 'N';
END;
and then
SELECT *
FROM lgsalary_history
WHERE is_valid( sal_from, 'dd-mon-yy' ) = 'N'

concatenate multiple clobs withing Oracle Procedure

I have an Oracle procedure that is going to accept multiple values within a parameter. Part of the procedure will run a select statement putting the results of the parameter in the where clause and placing the concatenated CLOBs into a variable. I am currently using the query below in the procedure but when I run it I get the error below.
If CLOB_ID is not null then
SELECT cast((collect(CLOB_TEXT) )as CLOB )
into v_MessageBody
FROM MESSAGE_CLOB_TABLE
WHERE MESSAGE_ID in CLOB_ID;
End If;
Error: ORA-00932: incosistant datatypes: expected - got CLOB
I also tried writing this using a LISTAGG function but LISTAGG doesnt work with the CLOB values in the MESSAGE_CLOB_TABLE
Any help would be greatly appreciated! I am using Oracle 11g.
If you need to concatenate in PL/SQL simplest variant is to loop through all selected records and append all found records to result:
create or replace function get_message(p_msg_id in number) return CLOB
is
v_MessageBody CLOB;
begin
-- create new instance of temporary CLOB
dbms_lob.createtemporary(v_MessageBody, true);
-- Fill instance with lines
for cMessages in (
select clob_text
from message_clob_table
where message_id = p_msg_id
order by message_row
)
loop
-- add line
dbms_lob.append(v_MessageBody, cMessages.clob_text);
end loop;
-- return collected lines as single CLOB
return v_MessageBody;
end;
Example above works if type of CLOB_TEXT field is CLOB and you need to collect only one message. You can test function in this SQLFiddle.
If you need to select many messages together based on list of his ID's, function becomes a little bit more complex, but principle remains the same.

Oracle dynamic PL/SQL. I cant get it to work

So here is my code:
CREATE OR REPLACE PROCEDURE UPDATE_USER
(
updateColumn IN USERS.column_name%type,
changeStr IN VARCHAR2,
unID IN VARCHAR2
)
IS
BEGIN
EXECUTE IMMEDIATE
'UPDATE
users
SET :1 = :2
WHERE
uniqueID = :3'
USING updateColumn, changeStr, unID;
END;
/
I've searched for other answers on this and as far as I can tell this should work. However I get the error:
'Error(3,25): PLS-00302: component 'COLUMN_NAME' must be declared'
Thanks.
The error message specifies line 3, character 25, which points to column_name in the declaration of the updateColumn parameter. It appears that you are trying to pass the column name to update as a parameter, but that means that at compile time the column isn't known, so its type can't be known. This also doesn't really make sense - if it's a number column then you'd be trying to pass the column name into a numeric parameter, which wouldn't work anyway. If you don't want to declare it as a simple varchar2, you could instead use user_tab_columns.column_name%type.
But you can't dynamically set the column name in the update statement using a bind variable. It would compile, but would get an ORA-01747 on execution from the apparent name starting with a colon. You'd need to concatenate it, something like:
CREATE OR REPLACE PROCEDURE UPDATE_USER
(
updateColumn IN user_tab_columns.column_name%type,
changeStr IN VARCHAR2,
unID IN VARCHAR2
)
IS
BEGIN
EXECUTE IMMEDIATE
'UPDATE
users
SET ' || updateColumn || ' = :1
WHERE
uniqueID = :2'
USING changeStr, unID;
END;
/
But you'd need to sanitise the column name to avoid SQL injection. APC's answer to the question you linked to mentions using the DBMS_ASSERT package, for example.

Resources