Oracle SQL developer debugging index table - sql

Is there a bug in SQL developer, or limitation
I'm trying to see values in index table fields, but it shows me only 20 fields???
here is my example code below I'm looping 30 time, but in debug screen shows only 20.
Does anyone know how I can see all fields?
CREATE OR REPLACE PROCEDURE TEST AS
TYPE Fieldvalue IS TABLE OF VARCHAR2 (100)
INDEX BY BINARY_INTEGER;
Field_Position Fieldvalue;
BEGIN
for i in 1..30 loop
Field_Position(i) := 'hello ' || i;
end loop;
dbms_output.put_line('hello');
END TEST;
I put debug break point on dbms_output.put_line('hello'); and it show only 20 records?

Without using the debug screen on sql developer, you can just loop through the array (field_position) to see its content.
CREATE OR REPLACE PROCEDURE TEST AS
TYPE Fieldvalue IS TABLE OF VARCHAR2 (100)
INDEX BY BINARY_INTEGER;
Field_Position Fieldvalue;
BEGIN
for i in 1..30 loop
Field_Position(i) := 'hello ' || i;
END loop;
FOR A IN FIELD_POSITION.FIRST..FIELD_POSITION.LAST
LOOP
DBMS_OUTPUT.PUT_LINE(FIELD_POSITION(A));
END LOOP;
END TEST;
/
BEGIN
TEST;
END;

Related

Handle a very large string in pl/sql script

I am trying to run below code which reads the index definition for table A so that it can be created again after I delete/create that in this script. This script runs fine when the returned value(ddl) is small but in other environments where the value is large with 140K characters in one row this script fails with below mentioned error. Please note that I cannot use spool in this case due to some restrictions. Could someone help on how to resolve this issue or suggest some another approach?
Thanks in advance.
"An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2)."
SET SERVEROUTPUT ON;
DECLARE
my_cursor SYS_REFCURSOR;
TYPE clob_array IS VARRAY(15) OF CLOB;
index_array clob_array := clob_array();
v_clob CLOB;
--index_array SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST();
BEGIN
OPEN my_cursor FOR 'select replace(dbms_metadata.get_ddl (''INDEX'', index_name), ''"C",'', '''')
from user_indexes
where table_name = ''A''';
LOOP FETCH my_cursor INTO v_clob;
EXIT WHEN my_cursor%NOTFOUND;
index_array.extend;
index_array(index_array.count) := v_clob;
dbms_output.put_line(index_array(index_array.count));
END LOOP;
CLOSE my_cursor;
END;
/
I simulated this issue you are getting this error because of the dbms_output.put_line which displays the output.Try switching to UTL_FILE at the server side OR Try for any alternatives
By the way, the code can be simplified to:
declare
type clob_array is table of clob;
index_array clob_array := clob_array();
begin
for r in (
select replace(dbms_metadata.get_ddl('INDEX', index_name), '"C",') as index_ddl
from user_indexes
where table_name = 'A'
)
loop
index_array.extend;
index_array(index_array.count) := r.index_ddl;
dbms_output.put_line(substr(index_array(index_array.count), 1, 32767));
end loop;
end;
I used substr() to limit the value passed to dbms_output.put_line to its documented limit. You could probably work around it by splitting the text into smaller chunks, and maybe finding the position of the last blank space before position 32767 in order to avoid splitting a word.
Here's what I came up with:
declare
type clob_array is table of clob;
index_array clob_array := clob_array();
procedure put_line
( p_text clob )
is
max_len constant simple_integer := 32767;
line varchar2(max_len);
remainder clob := p_text;
begin
while dbms_lob.getlength(remainder) > max_len loop
line := dbms_lob.substr(remainder,max_len);
line := substr(line, 1, instr(line, ' ', -1));
remainder := substr(remainder, length(line) +1);
dbms_output.put_line(line);
end loop;
if length(trim(remainder)) > 0 then
dbms_output.put_line(remainder);
end if;
end put_line;
begin
for r in (
select replace(dbms_metadata.get_ddl('INDEX', index_name), '"C",') as index_ddl
from user_indexes
where table_name = 'A'
)
loop
index_array.extend;
index_array(index_array.count) := r.index_ddl;
put_line(index_array(index_array.count));
end loop;
end;

How to select all rows from the oracle PL/SQL collection into SYS_REFCURSOR

Note: I have seen many solution and all says I can not use SQL with a PL/SQL type. I must have to use CREATE or REPLACE, but my restriction is I can not use system object for this task.
What I have tried the below example returns only last row.
create or replace PROCEDURE SP_TEST (TEST_cursor OUT SYS_REFCURSOR)IS
TYPE TEMP_RECORD IS RECORD(
entries NUMBER,
name VARCHAR2(50),
update VARCHAR2(200)
);
TYPE TEMP_TABLE IS TABLE OF TEMP_RECORD INDEX BY PLS_INTEGER;
VAR_TEMP TEMP_TABLE;
IDX PLS_INTEGER := 0;
BEGIN
VAR_TEMP(IDX).cur_entries := 1;
VAR_TEMP(IDX).cur_entries := 2;
OPEN TEST_cursor FOR
SELECT VAR_TEMP(idx).cur_entries from dual;
END SP_TEST;
Another way tried.
OPEN TEST_cursor FOR
SELECT * FROM TABLE(VAR_TEMP)
--- It gives compilation error ora-
Given that you can't create an object in the database, the only solution I can think of is to use dynamic SQL:
CREATE TYPE temp_record AS OBJECT
(
entries NUMBER,
entry_name VARCHAR2 (50),
update_value VARCHAR2 (200)
);
CREATE TYPE temp_table IS TABLE OF temp_record;
CREATE OR REPLACE PROCEDURE sp_test (test_cursor OUT SYS_REFCURSOR) IS
var_temp temp_table := temp_table ();
strSql VARCHAR2(32767);
BEGIN
-- Populate the temp table, or pass it in from elsewhere
var_temp.EXTEND();
var_temp (var_temp.LAST).entries := 1;
var_temp (var_temp.LAST).entry_name := 'test';
FOR i IN 1..var_temp.COUNT LOOP
strSql := strSql ||
CASE
WHEN LENGTH(strSql) > 0 THEN ' UNION ALL '
ELSE NULL
END ||
'SELECT ' || var_temp.ENTRIES || ' ENTRIES,' ||
'''' || var_temp.ENTRY_NAME || ''' ENTRY_NAME FROM DUAL';
END LOOP;
OPEN test_cursor FOR strSql;
END sp_test;
Now, I may have messed up the string concatenation logic there a bit, but the objective is to end up with an SQL string which looks something like
SELECT 1 ENTRIES,'test' ENTRY_NAME FROM DUAL
UNION ALL
SELECT 2 ENTRIES,'test 2' ENTRY_NAME FROM DUAL
UNION ALL
SELECT 3 ENTRIES,'test_3' ENTRY_NAME FROM DUAL
but, of course, without the nice white space and etc.
The 32K limit on dynamic SQL may bite you eventually, but if push comes to shove you can the DBMS_SQL package to handle arbitrarily large SQL text, although that presents its own challenges.
Best of luck.
In order to reference types in SQL (as opposed to PL/SQL), they must be created as objects in the database. This is effectively a scope issue: when you run SQL you are shifting to a different context. Any structures that you have created locally are not available there.
CREATE TYPE temp_record AS OBJECT
(
entries NUMBER,
entry_name VARCHAR2 (50),
update_value VARCHAR2 (200)
);
CREATE TYPE temp_table IS TABLE OF temp_record;
CREATE OR REPLACE PROCEDURE sp_test (test_cursor OUT SYS_REFCURSOR) IS
var_temp temp_table := temp_table ();
BEGIN
var_temp.EXTEND ();
var_temp (var_temp.LAST).entries := 1;
var_temp (var_temp.LAST).entry_name := 'test';
OPEN test_cursor FOR SELECT * FROM TABLE (var_temp);
END sp_test;

How to execute dynamic sql into cursor in Oracle?

I have problem with execute dynamic sql statement into sys_refcursor in my stored procedure.
I have looked in documentation and I think that I build my procedure properly, but I still do not know why error occurs.
Please look below, what I created:
CREATE TABLE REKOM_CROSS_PROM (
LINIA_PROD VARCHAR2(20),
ID_REKOM_OFERTA VARCHAR2(20),
PRICE NUMBER,
MAX_PRICE NUMBER
);
/
CREATE OR REPLACE TYPE prodType AS OBJECT (
p_line VARCHAR2(20)
,p_price NUMBER
);
/
CREATE OR REPLACE TYPE prodTypeList IS TABLE OF prodType;
/
CREATE OR REPLACE PROCEDURE my_proc (prodLines IN prodTypeList ,rekom OUT SYS_REFCURSOR)
IS
v_pLine VARCHAR2(20);
v_query VARCHAR2(4000);
BEGIN
v_query := 'SELECT ID_REKOM_OFERTA FROM REKOM_CROSS_PROM WHERE
LINIA_PROD=NULL';
FOR i IN 1 .. prodLines.COUNT
LOOP
v_pLine := prodLines(i).p_line;
v_query := v_query || ' UNION ALL SELECT ID_REKOM_OFERTA FROM
REKOM_CROSS_PROM WHERE LINIA_PROD=''' || v_pLine || '''';
END LOOP;
OPEN rekom FOR v_query;
END my_proc;
/
And when I want to call the procedure, error occur.
set serveroutput on
declare
type1 prodTypeList := prodTypeList(prodType('test1',1), prodType('test2', 20));
rc SYS_REFCURSOR;
row varchar2(200);
BEGIN
MY_PROC(type1, rc);
fetch rc into row;
while (rc%found) loop
dbms_output.put_line(row);
end loop;
close rc;
end;
I get the message:
ORA-20000: ORU-10027: buffer overflow, limit of 1000000 bytes
*Cause: The stored procedure 'raise_application_error'
was called which causes this error to be generated.
*Action: Correct the problem as described in the error message or contact
the application administrator or DBA for more information.
Can sombody help me to resolve the problem?
You have an infinite loop. That means you're calling dbms_output.put_line forever - or until it runs out of buffer space, and throws that exception.
BEGIN
MY_PROC(type1, rc);
-- fetch first row from result set
fetch rc into row;
-- check if last fetch found something - always true
while (rc%found) loop
dbms_output.put_line(row);
end loop;
close rc;
end;
Every time around the loop you're checking the result of that first fetch, which stays true (assuming there is any data). You need to fetch each time round the loop:
BEGIN
MY_PROC(type1, rc);
-- fetch first row from result set
fetch rc into row;
-- check if last fetch found something
while (rc%found) loop
dbms_output.put_line(row);
-- fetch next row from result set
fetch rc into row;
end loop;
close rc;
end;
Or perhaps more commonly, only fetch inside the loop, and stop when nothing is found, using %notfound rather than %found:
BEGIN
MY_PROC(type1, rc);
loop
-- fetch row from result set
fetch rc into row;
-- check if last fetch found something
exit when rc%notfound;
dbms_output.put_line(row);
end loop;
close rc;
end;
Not related to your current issue, but the predicate WHERE LINIA_PROD=NULL is never true; null isn't equal to (or not equal to) anything else. You need to use WHERE LINIA_PROD IS NULL instead.

How do I view a CLOB output parameter in TOAD from an Oracle Stored Procedure?

I have a stored procedure in a package in an Oracle database that has 2 input parameters + 1 output CLOB parameter. How do I view the output in Toad? (Preferably with the user only having execute/select permissions)
Solution:
DECLARE
my_output_parameter CLOB;
BEGIN
my_package.my_stored_proc(1, 2, my_output_parameter);
DBMS_OUTPUT.PUT_LINE(my_output_parameter);
END;
Don't forget to execute as script, rather than just execute statement, and results appear in the DBMS Output window, not the datagrid.
I guess DBMS_OUTPUT.PUT_LINE has an internal line limit of 255 chars. However it has been removed from 10g Release 2 onwards. You can try inserting the column data in a table and view it later on by querying that table.
Please refer -
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:146412348066
Would you consider printing the CLOB as a result set? You could then use a PIPELINED function (more about them here: PIPELINED functions by Tim Hall) which would return the CLOB line by line, take a look at the example below:
CREATE TABLE my_clob_tab (
id NUMBER,
clob_col CLOB
)
/
INSERT INTO my_clob_tab
VALUES (1,
to_clob('first line' || chr(10) ||
'second line, a longer one' || chr(10) ||
'third'))
/
CREATE OR REPLACE TYPE t_my_line_str AS TABLE OF VARCHAR2(2000)
/
CREATE OR REPLACE FUNCTION print_clob_func(p_id IN NUMBER)
RETURN t_my_line_str PIPELINED
AS
v_buffer VARCHAR2(32767);
v_clob CLOB;
v_len NUMBER;
v_offset NUMBER := 1;
v_line_break_pos NUMBER;
v_amount NUMBER;
BEGIN
SELECT clob_col
INTO v_clob
FROM my_clob_tab
WHERE id = p_id;
IF v_clob IS NOT NULL THEN
v_len := dbms_lob.getlength(v_clob);
WHILE v_offset < v_len
LOOP
v_line_break_pos := instr(v_clob, chr(10), v_offset);
IF v_line_break_pos = 0 THEN
v_amount := v_len - v_offset + 1;
ELSE
v_amount := v_line_break_pos - v_offset;
END IF;
dbms_lob.read(v_clob, v_amount, v_offset, v_buffer);
v_offset := v_offset + v_amount + 1;
PIPE ROW (v_buffer);
END LOOP;
END IF;
END;
/
(the function can be changed so that it takes as a parameter the CLOB you get from your procedure)
The code reads the content of the CLOB line by line (I assumed that the line separator is CHR(10) - if you are on Windows, you can change it to CHR(10) || CHR(13)) and PIPEs each line to the SELECT statement.
The function that reads the clob could also print the output to the standard output via dbms_output.put_line, but it would be trickier, because you'd have to take into account that standard output's maximal line length is limitied to, correct me if I'm wrong, 2000 characters, but it is doable (can't try that solution right now, unfortunately). In the meanwhile, please check above proposal and give me some feedback if that would work for you.
Back to the solution, now we can issue this SELECT statement:
SELECT COLUMN_VALUE AS clob_line_by_line FROM TABLE(print_clob_func(1));
Which will give us the following output:
CLOB_LINE_BY_LINE
-------------------------
first line
second line, a longer one
third
Check it at SQLFiddle: SQLFiddle example
Approach with inserting PL/SQL block and dbms_output:
DECLARE
my_output_parameter CLOB;
BEGIN
my_package.my_stored_proc(1, 2, my_output_parameter);
declare
vClob CLOB := my_output_parameter;
vPos number;
vLen number;
begin
vLen := DBMS_LOB.GetLength(vClob);
vPos := 1;
while vPos < vLen loop
DBMS_OUTPUT.Put(DBMS_LOB.Substr(vCLOB, 200, vPos));
vPos := vPos + 200;
end loop;
DBMS_OUTPUT.new_line;
end;
END;

How to remove more than one space in Oracle

I have an Oracle table which contains data like 'Shiv------Shukla' (consider '-' as space).
Now I need to write a program which leaves just one space and removes all other spaces.
Here is the program which I've made but it is not giving me expected result.
DECLARE
MAX_LIMIT VARCHAR2(50):=NULL;
REQ VARCHAR2(20):=NULL;
CURSOR C1 IS
SELECT *
FROM ASSET_Y;
BEGIN
FOR REC IN C1
LOOP
MAX_LIMIT:=LENGTH(REC.NAME)-LENGTH(REPLACE(REC.NAME,'-'));
FOR I IN 1..MAX_LIMIT
LOOP
UPDATE ASSET_Y
SET NAME=REPLACE(REC.NAME,'--','-')
WHERE REC.SNO=ASSET_Y.SNO;
COMMIT;
SELECT ASSET_Y.NAME INTO REQ FROM ASSET_Y WHERE ASSET_Y.SNO=REC.SNO;
DBMS_OUTPUT.PUT_LINE(REQ);
END LOOP;
END LOOP;
COMMIT;
END;
/
My table is
SQL> select * from asset_y;
SNO NAME FL
---------- -------------------- --
1 Shiv------Shukla y
2 Jinesh y
after running the procedure i m getting the following output.
Shiv---Shukla
Shiv---Shukla
Shiv---Shukla
Shiv---Shukla
Shiv---Shukla
Shiv---Shukla
PL/SQL procedure successfully completed.
Since regexp_replace is not available in Oracle 9i maybe you can use owa_pattern routines for simple regex replaces:
owa_pattern.change(fStr, '\s+', ' ', 'g');
More info about owa_pattern package can be found here
Bear in mind, that "\s" will match tabs and newlines as well.
With Oracle 9 you could write your own function:
CREATE FUNCTION remove_multi_spaces( in_value IN VARCHAR2 )
RETURN VARCHAR2
AS
v_result VARCHAR2(32767);
BEGIN
IF( in_value IS NOT NULL ) THEN
FOR i IN 1 .. ( LENGTH(in_value) - 1 ) LOOP
IF( SUBSTR( in_value, i, 2 ) <> ' ' ) THEN
v_result := v_result || SUBSTR( in_value, i, 1 );
END IF;
END LOOP;
v_result := v_result || SUBSTR( in_value, -1 );
END IF;
RETURN v_result;
END;
and call it in a single update-statement:
UPDATE asset_y
SET name = replace_multi_spaces( name );
BTW: With Oracle 10 you could use REGEXP_REPLACE.
Your problem is this part:
SET NAME=REPLACE(REC.NAME,'--','-')
However many times you do that within the inner loop it starts with the same value of REC.NAME as before. Changing it to this would fix it:
SET NAME=REPLACE(NAME,'--','-')
However, it is a pretty inefficient way to do this job if the table is large. You could instead do this:
BEGIN
LOOP
UPDATE ASSET_Y
SET NAME=REPLACE(NAME,'--','-')
WHERE NAME LIKE '%--%';
EXIT WHEN SQL%ROWCOUNT = 0;
END LOOP;
END;
/
Another way:
CREATE OR REPLACE
FUNCTION remove_multi_spaces( in_value IN VARCHAR2 )
RETURN VARCHAR2 IS
v_result VARCHAR2(32767) := in_value;
BEGIN
LOOP
EXIT WHEN INSTR(v_result,' ') = 0;
v_result := REPLACE(v_result, ' ', ' ');
END LOOP;
RETURN v_result;
END remove_multi_spaces;
Ack loops! No need to loop this
This will work in T-SQL...unfortunately I have no pl/sql environment to write this in. PL/SQL will have equivlents to everything used here (I think substr instead of substring and | instead of +)
declare #name varchar(200)
set #name = 'firstword secondword'
select left(#name,(patindex('% %',#name)-1)) + ' ' + ltrim(substring(#name,(patindex('% %',#name)+1),len(#name)))
You'll have to retool it to work for oracle and you'll need to replace any reference to #name to asset_y.name
select left(asset_y.name,(patindex('% %',asset_y.name)-1)) || ' ' || ltrim(substring(asset_y.name,(patindex('% %',asset_y.name)+1),len(asset_y.name)))
Sorry if it won't run as is, as I mentioned I lack an oracle install here to confirm...
Just to add...I normally turn that query above into a function named formatname and call it as select formatname(array_y.name) from... This allows me to include some form of error handling. The query will fail if patindex('% %',array_v.name) returns a null...meaning there is no space. You could do the same in a select statement using cases I guess:
select case when patindex('% %',array_v.name) > 0 then
left(asset_y.name,(patindex('% %',asset_y.name)-1)) || ' ' || ltrim(substring(asset_y.name,(patindex('% %',asset_y.name)+1),len(asset_y.name)))
else asset_y.name
from...