PL/SQL if table not exist create - sql

Hello i use oracle SQL developer
I have create a procedure, and i need to check if a table exist, if not exist i must create how can do?
I have try this
DECLARE v_emp int:=0;
BEGIN
SELECT count(*) into v_emp FROM dba_tables;
if v_emp = 0 then
EXECUTE IMMEDIATE 'create table EMPLOYEE ( ID NUMBER(3), NAME VARCHAR2(30) NOT NULL)';
end if;
END;
but give me an error 00103 because not find table

Just execute the create and watch the exception if thrown. Oracle would never replace the DDL of a table.
declare
error_code NUMBER;
begin
EXECUTE IMMEDIATE 'CREATE TABLE EMPLOYEE(AGE INT)';
exception
when others then
error_code := SQLCODE;
if(error_code = -955)
then
dbms_output.put_line('Table exists already!');
else
dbms_output.put_line('Unknown error : '||SQLERRM);
end if;
end;

You can run this for example:
if (select count(*) from all_tables where table_name = 'yourTable')>0 then
-- table exists
else
-- table doesn't exist
end if;

You should try following,
declare
nCount NUMBER;
v_sql LONG;
begin
SELECT count(*) into nCount FROM dba_tables where table_name = 'EMPLOYEE';
IF(nCount <= 0)
THEN
v_sql:='
create table EMPLOYEE
(
ID NUMBER(3),
NAME VARCHAR2(30) NOT NULL
)';
execute immediate v_sql;
END IF;
end;

Related

Execute immediate statement

I'm trying to insert data into table using execute immediate statement. But I get an error
FROM keyword not found where expected
Could anyone take a look what's wrong?
declare
c1 SYS_REFCURSOR;
v_tabl_name varchar2(30);
begin
open c1 for
select tablename from table1;
LOOP
FETCH c1 INTO v_tabl_name;
EXIT WHEN c1%NOTFOUND;
execute immediate 'insert tabl2(tabl_name) (select ''tem'' from'||v_tabl_name||')' ;
END LOOP;
close c1;
end;
create table table1(tem varchar2(50), tablename varchar2(50));
create table tabl2(tabl_name varchar2(50));
insert into table1(tem, tablename) values ('table1','table1');
begin
for rc in (select tablename from table1) loop
--dbms_output.put_line('insert into tabl2(tabl_name) (select ''tem'' from '||rc.tablename||')');
execute immediate 'insert into tabl2(tabl_name) (select ''tem'' from '||rc.tablename||')' ;
end LOOP;
end;

Cursor inside procedure body

I am trying to declare a cursor inside procedure body.
I know it is supposed to be done in the declare block but the table the cursor refers is created inside the procedure body.
--TABLE MAY OR MAY NOT BE PRESENT PRIOR TO PROCEDURE EXECUTION
SELECT COUNT(*)
INTO ln_cnt
FROM User_Tables
WHERE table_name = 'TMP$UOM_COMBO_GEN';
IF ln_cnt > 0 THEN
EXECUTE IMMEDIATE ' CREATE TABLE TMP$UOM_COMBO_GEN (UOM_ID VARCHAR2(20 BYTE), HIER_CODE VARCHAR2(20 BYTE),NODE_CODE VARCHAR2(200 BYTE))';
END IF;
CURSOR C_HIER
IS
SELECT DISTINCT HIER_CODE FROM TMP$UOM_COMBO_GEN WHERE UOM_ID=P_UOM_ID;
FOR HIER IN C_HIER
LOOP
IF C_HIER%ROWCOUNT = 1 THEN
LV_SQL2 := '(SELECT UOM_ID, NODE_CODE '||HIER.HIER_CODE||' FROM TMP$UOM_COMBO_GEN WHERE UOM_ID='''||P_UOM_ID||''' AND HIER_CODE='''||HIER.HIER_CODE||''')'||HIER.HIER_CODE;
LV_SORT := ' ORDER BY '||HIER.HIER_CODE||'';
LV_SQL := 'SELECT * FROM ' || LV_SQL2;
ELSE
LV_SQL3 := ' LEFT OUTER JOIN(SELECT NODE_CODE '||HIER.HIER_CODE||' FROM TMP$UOM_COMBO_GEN WHERE UOM_ID='''||P_UOM_ID||''' AND HIER_CODE='''||HIER.HIER_CODE||''')'||HIER.HIER_CODE ||' ON 1=1';
LV_SORT := LV_SORT||','||HIER.HIER_CODE||'';
LV_SQL := LV_SQL || LV_SQL3;
END IF;
END LOOP;
I am getting the following error.
Error(17,10): PLS-00103: Encountered the symbol "C_HIER" when expecting one of the following: := . ( # % ;
Well a table once created is stored in database and u can refer it from wherever u want to refer in the schema .
Also there a change may be required in your code in the following part
SELECT COUNT(*)
INTO ln_cnt
FROM User_Tables
WHERE table_name = 'TMP$UOM_COMBO_GEN';
IF ln_cnt > 0 THEN -- means only if table exists u want to create the table which will
--throw an exception if table is already there ,
--so better equate it to 0
EXECUTE IMMEDIATE ' CREATE TABLE TMP$UOM_COMBO_GEN (UOM_ID VARCHAR2(20 BYTE), HIER_CODE VARCHAR2(20 BYTE),NODE_CODE VARCHAR2(200 BYTE))';
END IF;
Now , if u really have a requirement to create a new table every time some condition is true/false and u then want to select the table in a cursor do something like following by using reference cursors
create or replace procedure abc(Table_name varchar2 , param_list varchar2 , where_clause varchar2) is
c_hier sys_refcursor ;
LV_SQL2 varchar2(2000) ;
LV_SORT varchar2(2000) ;
LV_SQL varchar2(2000) ;
LV_SQL3 varchar2(2000) ;
begin
SELECT COUNT(*)
INTO ln_cnt
FROM User_Tables
WHERE table_name = Table_name; -- Use any table here
IF ln_cnt = 0 THEN
EXECUTE IMMEDIATE ' CREATE TABLE '||Table_name||' '||param_list;
END IF;
open c_hier for 'SELECT DISTINCT '||param_list||' FROM '||table_name||' '||where_clause;
FOR HIER IN C_HIER
LOOP
IF C_HIER%ROWCOUNT = 1 THEN
LV_SQL2 := '(SELECT UOM_ID, NODE_CODE '||HIER.HIER_CODE||' FROM TMP$UOM_COMBO_GEN WHERE UOM_ID='''||P_UOM_ID||''' AND HIER_CODE='''||HIER.HIER_CODE||''')'||HIER.HIER_CODE;
LV_SORT := ' ORDER BY '||HIER.HIER_CODE||'';
LV_SQL := 'SELECT * FROM ' || LV_SQL2;
ELSE
LV_SQL3 := ' LEFT OUTER JOIN(SELECT NODE_CODE '||HIER.HIER_CODE||' FROM TMP$UOM_COMBO_GEN WHERE UOM_ID='''||P_UOM_ID||''' AND HIER_CODE='''||HIER.HIER_CODE||''')'||HIER.HIER_CODE ||' ON 1=1';
LV_SORT := LV_SORT||','||HIER.HIER_CODE||'';
LV_SQL := LV_SQL || LV_SQL3;
END IF;
END LOOP;

How to put string of values with IN clause using dynamic PL/SQL?

Using Oracle PL/SQL, how can I populate the bind variable :b3 with more than one value for the IN clause? (This code is for demo purposes only -- it may not compile but it does clarify the question if any is needed)
declare
type work_rec is record (
work_status varchar2(50),
work_cd varchar2(50));
type work_tab is table of work_rec index by pls_integer;
t_work_tab work_tab;
sql_stmt varchar2(400);
begin
select case
when status_desc like '%Employed%' then 'Employed'
else 'Unknown'
end as work_status
,case
when status_cd between '1' and '9' then '1,2,3,4'
else '0'
end as work_cd
bulk collect into t_work_tab
from employee_table;
for i in t_work_tab.first..t_work_tab.last
loop
sql_stmt := 'insert into employee_hist
select name,
employer
from tax_table
where employment_cd in (:b3)'; --< how to populate this with '1','2','3','4'
execute immediate sql_stmt using t_work_tab(i).work_cd;
commit;
end loop;
end;
/
When you loop through the values, keep appending the string with ' and , as required to make up the part of in. Then you can use that string as part of your sql statement.
Example
temp = "'"
Loop through values a,b,c,d as str
temp = temp + str + "'",
End Loop
temp = substr(temp,0,length(temp)) // this is to trim the last , character
Hope it helps!
You need to prepare the in list inside the loop using another variable and then the statement outside it. Something like this may help:
declare
type work_rec is record (
work_status varchar2(50),
work_cd varchar2(50));
type work_tab is table of work_rec index by pls_integer;
t_work_tab work_tab;
sql_stmt VARCHAR2(400);
v_in_str varchar2(100);_
begin
select case
when status_desc like '%Employed%' then 'Employed'
else 'Unknown'
end as work_status
,case
when status_cd between '1' and '9' then '1,2,3,4'
else '0'
end as work_cd
bulk collect into t_work_tab
from employee_table;
for i in t_work_tab.first..t_work_tab.last
loop
v_in_str := v_in_str || t_work_tab(i).work_cd || ',';
END loop;
v_in_str :=rtrim(v_in_str, ',');
sql_stmt := 'insert into employee_hist
select name,
employer
from tax_table
where employment_cd in ('||v_in_str||')';
execute immediate sql_stmt;
commit;
end;
you could use a plsql collection as bind variable, this seems the nicer solution to me:
declare
type t_nbr_tbl is table of number;
type work_rec is record (
work_status varchar2(50),
work_cd t_nbr_tbl;
type work_tab is table of work_rec index by pls_integer;
t_work_tab work_tab;
sql_stmt varchar2(400);
begin
select case
when status_desc like '%Employed%' then 'Employed'
else 'Unknown'
end as work_status
,case
when status_cd between '1' and '9' then t_nbr_tbl(1,2,3,4)
else t_nbr_tbl(0)
end as work_cd
bulk collect into t_work_tab
from employee_table;
for i in t_work_tab.first..t_work_tab.last
loop
sql_stmt := 'insert into employee_hist
select name,
employer
from tax_table
where employment_cd in (select column_value from table(:b3))'; --< how to populate this with '1','2','3','4'
execute immediate sql_stmt using t_work_tab(i).work_cd;
commit;
end loop;
end;
/
Better solution (at least to my issue) - don't use a bind variable but instead concatenate the string of values (code segment shown only):
for i in t_work_tab.first..t_work_tab.last
loop
sql_stmt := 'insert into employee_hist
select name,
employer
from tax_table
where employment_cd in (' || t_work_tab(i).work_cd || ')';
execute immediate sql_stmt;
...
You get the idea. Thanks for all your input.

Cursor and table cannot be found

I have a procedure that will select MAX from some tables, but for some reason it is not able to find these tables. Could anybody help me?
declare
varible1 varchar2 (255);
temp varchar2 (255);
last_val number(9,0);
cursor c1 is Select distinct table_name from user_tab_cols order by table_name;
begin
FOR asd in c1
LOOP
temp := asd.table_name;
varible1 := '"'||temp||'"';
select max("id") into last_val from varible1 ;
END LOOP;
end;
For example, the first table name is acceptance_form and for select I need to use "acceptance_form".
Code after edit:
declare
varible1 varchar2 (255);
temp varchar2 (255);
last_val number(9,0);
cursor c1 is Select distinct table_name from user_tab_cols where column_name = 'id';
begin
FOR asd in c1
LOOP
temp := asd.table_name;
execute immediate 'select NVL(max('||'id'||'),0) from "'||varible1||'"' into last_val;
END LOOP;
end;
Can't cuz db is Case sensitive Oracle express 10g tables and rows was created like this
CREATE TABLE "ADMINMME"."acceptance_form"
(
"group_id" NUMBER(9, 0),
"id" NUMBER(4, 0) DEFAULT '0' NOT NULL ,
"is_deleted" NUMBER(4, 0),
"name" NVARCHAR2(30) NOT NULL
);
Can u tell me how to handle exception sequence dosn't exist for this;
Nevermind exception was in wrong block :)
declare
temp varchar2 (255);
last_val number(9,0);
cursor c1 is Select distinct table_name from user_tab_cols where column_name = 'id';
begin
FOR asd in c1
LOOP
temp := asd.table_name;
execute immediate 'select NVL(max("id"),0)+1 from "'||temp||'"' into last_val;
begin
EXECUTE IMMEDIATE 'drop sequence "seq_'|| temp||'"';
EXECUTE IMMEDIATE 'create SEQUENCE "seq_'|| temp ||'" MINVALUE '||last_val||'MAXVALUE 999999999999999999999999999 INCREMENT BY 1 NOCACHE';
EXECUTE IMMEDIATE 'select '||temp||'.nextval from dual';
EXECUTE IMMEDIATE 'ALTER SEQUENCE "seq_'||temp||'" INCREMENT BY 1';
exception when others then
null;
end;
END LOOP;
end;
Dynamic sql doesn't work in that way.
declare
varible1 varchar2 (255);
temp varchar2 (255);
last_val number(9,0);
cursor c1 is Select distinct table_name from user_tab_cols order by table_name;
begin
FOR asd in c1
LOOP
temp := asd.table_name;
begin
execute immediate 'select max(id) from '||temp into last_val;
dbms_output.put_line('max(id) for table: ' ||temp||' = '||last_val);
exception when others then
dbms_output.put_line('Failed to get max(id) for table: ' ||temp);
end;
END LOOP;
end;
You can't use a variable for the table name.
What you can do is creating the complete sql statement as a string and use execute immediate
Here are some examples how to do that: http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/dynamic.htm#CHDGJEGD

Catching an exception while altering a table in Oracle

I'm trying to write a command in Oracle that will wither ADD or MODIFY a column depending on whether or not it already exists. Basically something like:
BEGIN
ALTER TABLE MY_TABLE ADD ( COL_NAME VARCHAR2(100 );
EXCEPTION WHEN OTHERS THEN
ALTER TABLE MY_TABLE MODIFY ( COL_NAME VARCHAR2(100) );
END;
However, Oracle complains about having the ALTER command inside of BEGIN. Is there a way to achieve this using a single SQL command in Oracle?
Thanks!
In order to put DDL in a PL/SQL block, you would need to use dynamic SQL.
Personally, I'd check whether the column exists first and then issue the DDL. Something like
DECLARE
l_cnt INTEGER;
BEGIN
SELECT COUNT(*)
INTO l_cnt
FROM dba_tab_cols
WHERE table_name = 'MY_TABLE'
AND owner = <<owner of table>>
AND column_name = 'COL_NAME';
IF( l_cnt = 0 )
THEN
EXECUTE IMMEDIATE 'ALTER TABLE my_table ADD( col_name VARCHAR2(100) )';
ELSE
EXECUTE IMMEDIATE 'ALTER TABLE my_table MODIFY( col_name VARCHAR2(100) )';
END IF;
END;
If you don't have access to DBA_TAB_COLS, you could also use ALL_TAB_COLS or USER_TAB_COLS depending on what schema the table resides in and what privileges you have on the table.
I found a solution based on this post.
DECLARE v_column_exists number := 0;
BEGIN
SELECT COUNT(*) INTO v_column_exists
FROM ALL_TAB_COLUMNS
WHERE TABLE_NAME = 'MY_TABLE'
AND COLUMN_NAME = 'COL_NAME';
IF (v_column_exists = 0) THEN
EXECUTE IMMEDIATE 'ALTER TABLE MY_TABLE ADD ( COL_NAME VARCHAR2(200) )';
ELSE
EXECUTE IMMEDIATE 'ALTER TABLE MY_TABLE MODIFY ( COL_NAME VARCHAR2(200) )';
END IF;
END;