I'm trying to implement a pl sql program that export the content of all tables of a particular user in a file but i'm getting 'command not properly ended' problem whenever i run it.
here is my code:
create or replace procedure userTable(name dba_tables.owner%type)
is
cursor cur1 is select table_name from dba_tables where owner = upper(name);
cursor cur(tabName in varchar2) is select column_name from dba_tab_columns where owner = upper(name) and table_name = upper(tabName);
V$FILEP UTL_FILE.FILE_TYPE;
type dyncursor is ref cursor;
dyn dyncursor;
req varchar2(32767):='select to_char(';
lig Varchar2(32767);
i integer:=1;
begin
if existUser(name) = true then
V$FILEP := UTL_FILE.FOPEN('DIRT001','TEST09.UTL','W');
for vc1 in cur1 loop
for vc in cur(to_char(vc1.table_name)) loop
if (i=1) then
req:=req||vc.column_name||')';
i:=0;
else
req:=req||'||'||''','''||'||'||'to_char('||vc.column_name||')';
end if;
end loop;
req:=req||' from '||name||'.'||'to_char('||vc1.table_name||')';
open dyn for req;
loop
fetch dyn into lig;
exit when dyn%notfound;
dbms_output.put_line(lig);
UTL_FILE.PUT_LINE(V$FILEP,lig );
end loop;
close dyn;
end loop;
UTL_FILE.FCLOSE(V$FILEP);
else
dbms_output.put_line('user invalid');
end if;
end;
/
create or replace function existUser(name dba_users.username%type)
return boolean is
nb number :=0;
begin
select count(*) into nb from dba_users where username = upper(name);
if nb = 0 then
return false;
else
return true;
end if;
end;
/
Expanding on what has been mentioned in the comments, adding a DBMS_OUTPUT is going to show you that you have 'from schema.to_char(table_name)'.....
vc1.table_name & vc.column_name are already character (varchar2) so there is no need to do a to_char on them in the first place so just removing to_char from around all these is a good first step.
Then if it still does not work add the DBMS_OUTPUT as suggested by Arkadiusz Ćukasiewicz in the comments to see what other issues you may have.
Related
I wrote simple program in PL/SQL to reduce price. When I call procedure I intentionally pass arguments which are not in database, so cursor doesn't return any data.
Here is problem: my exception not working. Expression like kursor%notfound check if kursor not returns any data or is not declared?
I am confused, because while I was doing research some people said that kursor%notfound returns true when there is no data found, but in my program it doesn't work. When it comes to this:
if (kursor%notfound) then
raise no_data_found;
end if;
It doesn't raise exception. What am I doing wrong?
PS Sorry for inconsistency according to language(mixing polish and english) , but I have database in polish.
My whole program:
set serveroutput on
create or replace procedure reduce_price(surname_p varchar2,
name_p varchar2, percents number default 5)is
cursor kursor is
select n.id_mech,cena from naprawa n
join mechanik m on m.id_mech = n.id_mech
where m.imie = name_p and m.nazwisko = surname_p
for update;
nc number;
begin
for k in kursor
loop
if (kursor%notfound) then
raise NO_DATA_FOUND;
end if;
begin
nc := k.cena *(1-percents/100);
dbms_output.put_line(k.cena ||' ' ||nc);
update naprawa set cena =nc
where id_mech = k.id_mech;
exception
when NO_DATA_FOUND then
dbms_output.put_line('no rows found');
end;
end loop;
end;
/
begin
reduce_price('aaa', 'XYZ',1);
end;
Thanks for your time.
That's not going to work. in your cursor for loop, if your code enters the loop, then that implies that one or more records where found, and %notfound cursor attribute will never be true. You have a couple of options.
keep a counter in the loop and check after exit
create or replace procedure reduce_price(surname_p varchar2,
name_p varchar2, percents number default 5)is
nc number;
cnt number := 0;
begin
for k in kursor
loop
nc := k.cena *(1-percents/100);
dbms_output.put_line(k.cena ||' ' ||nc);
update naprawa set cena =nc
where id_mech = k.id_mech;
cnt := cnt + 1;
end loop;
if cnt = 0 then
raise NO_DATA_FOUND;
end if;
.. etc..
check for a existing data before entering the loop
select count(*)
into cnt
from naprawa n
join mechanik m on m.id_mech = n.id_mech
where m.imie = name_p and m.nazwisko = surname_p;
if cnt = 0 then
raise NO_DATA_FOUND;
end if;
...
for k in kursor
loop
I have written the code below to correct all table in my db.
Please review and correct it.
Declare
Name Varchar2(100);
A Number:=0;
Cursor C1 Is
Select Table_Name From Tabs;
Begin
Open C1;
Loop
A:=A+1;
Fetch C1 Into Name;
Exit When C1%Notfound;
Execute Immediate 'Create Or Replace View Tab||A
As
Select * From Name';
End Loop;
Close C1;
End
Please correct my Code
This forum is not a place to give people assigments, please ask questions about the issue you are running into and we are willing to help you. Please try doing a better job next time.
Your execute immediate string should be:
Execute Immediate
'Create Or Replace View Tab' ||A|| '
As
Select * From ' || Name;
and don't forget the ; after the final end
fixed your code:
Declare
Name Varchar2(100);
A Number:=0;
Cursor C1 Is
Select Table_Name From Tabs;
Begin
Open C1;
Loop
A:=A+1;
Fetch C1 Into Name;
Exit When C1%Notfound;
Execute Immediate 'Create Or Replace View Tab'||A||'
As
Select * From "'||Name||'"';
End Loop;
Close C1;
End;
/
But I would do something like this:
declare
procedure p_exec(pCMD in varchar2, pPrintOnly varchar2 default 'n') is
begin
if pPrintOnly='y' then
dbms_output.put_line(pCMD);
else
execute immediate pCMD;
dbms_output.put_line(pCMD);
end if;
end;
begin
for r in (Select rownum rn, Table_Name From Tabs) loop
p_exec(
utl_lms.format_message(
'Create Or Replace View Tab%s As Select * From "%s"'
, to_char(r.rn,'fm9999')
, r.table_name
)
-- ,'y' -- << uncomment to print commands only without execution
);
end loop;
end;
/
I need to run below code on different environments and it works fine when table1 exists but when it does not exist then it throws error in cursor declaration that "table or view does not exist".
I am running this on Oracle.
Could you please help me in correcting this?
Thanks in advance.
DECLARE
CURSOR my_cursor IS (select "col1" from "table1");
name1 VARCHAR2(256);
tableCount NUMBER;
BEGIN
Select count(*) into tableCount from user_tab_cols where table_name = 'table1' and column_name = 'col2';
IF tableCount > 0 THEN
OPEN my_cursor;
LOOP
FETCH my_cursor into name1;
EXIT WHEN my_cursor%notfound;
-- Update or delete statement here
DBMS_OUTPUT.PUT_LINE('value is ' || name1);
END LOOP;
CLOSE my_cursor;
END IF;
END;
/
A CURSOR with a defined return type is strongly typed. Sys_refcursors are weakly typed. This means that any return type in a CURSOR must be valid. A SYS_REFCURSOR is more flexible and can be defined at a later time.
When setting a CURSOR in the declaration section, you must use a SQL statement that will execute properly. In this case, you are setting the CURSOR to select a column from a table that does not exist. The database execution will not reach the body of the code since it errors prior to exiting the declaration block.
To fix this, use a SYS_REFCURSOR with a dynamic sql query, as mentioned by Tejash above. This allows you to check to see if the table exists before setting the cursor. If the table exists, set the cursor to select from the specified table. If it doesn't, output a message saying that it does not exist.
Note that you can also use the SQL error codes, as shown in other answers. I prefer personally to handle business rules in the logic prior to the error occurring.
DECLARE
my_cursor sys_refcursor;
name1 VARCHAR2(256);
tableCount NUMBER;
BEGIN
Select count(*) into tableCount from user_tab_cols where table_name = 'table1' and column_name = 'col2';
IF tableCount > 0 THEN
OPEN my_cursor for 'select order_id from table1';
LOOP
FETCH my_cursor into name1;
EXIT WHEN my_cursor%notfound;
-- Update or delete statement here
DBMS_OUTPUT.PUT_LINE('value is ' || name1);
END LOOP;
CLOSE my_cursor;
else
dbms_output.put_line('Table does not exist');
END IF;
END;
http://docs.oracle.com/database/122/LNPLS/static-sql.htm#LNPLS568
You can use the exceptions and dynamic string for a cursor as follows:
DECLARE
MY_CURSOR SYS_REFCURSOR;
NAME1 VARCHAR2(256);
TABLECOUNT NUMBER;
BEGIN
OPEN MY_CURSOR FOR 'SELECT ACC_NR FROM ACCOUNT'; -- dynamic string for cursor
LOOP
FETCH MY_CURSOR INTO NAME1;
EXIT WHEN MY_CURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('value is ' || NAME1);
END LOOP;
CLOSE MY_CURSOR;
EXCEPTION -- exception handling using SQLCODE
WHEN OTHERS THEN
IF SQLCODE = -942 THEN
DBMS_OUTPUT.PUT_LINE('Table does not exists');
ELSIF SQLCODE = -904 THEN
DBMS_OUTPUT.PUT_LINE('Invalid column name');
ELSE
DBMS_OUTPUT.PUT_LINE('Other error');
END IF;
END;
/
I have a function that returns a list of records, and then im looping over the list and piping them, however during piping I am getting ORA-01403: no data found error.
Below is the code I am using, and I am getting this error on some rows, not all of them.
NOTE: tab_pipe.t_tab and tab.t_tab are tables of the same record tab.r_tab.
Function pipelinedFunction(ref varchar2, seq varchar2) Return tab_pipe.t_tab pipelined Is
pragma autonomous_transaction;
errtxt varchar2(400);
tab tab.t_tab;
begin
tab := generate_table(ref, seq);
for i in 1 .. tab.count loop
begin
pipe row(tab(i));
EXCEPTION
when others then
v_errtxt := sqlerrm;
insert into test_kc values('an error occurred piping the row i = ' || i || ' - sqlerrm = ' || v_errtxt); commit;
end;
end loop;
return;
end pipelinedFunction;
Maybe there is no entry in tab for every value of i.
Try a loop using first and next
declare
l_index PLS_INTEGER;
BEGIN
l_index := tab.FIRST;
WHILE (l_index IS NOT NULL)
LOOP
pipe row(tab(l_index));
l_index := tab.NEXT(l_index);
END LOOP;
END;
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...