Creating database table in PL/SQL procedure - sql

I am trying to create table with procedure CREATE_TABLE and then insert the information into the created table with procedure PRINT_INFO but I am getting an exception:
Errors: PROCEDURE PRINT_INFO Line/Col: 4/3 PL/SQL: SQL Statement
ignored Line/Col: 4/15 PL/SQL: ORA-00942: table or view does not exist
Errors: PROCEDURE CREATE_TABLE Line/Col: 5/3 PLS-00103: Encountered
the symbol "CREATE" when expecting one of the following:
( begin case declare exit for goto if loop mod null pragma raise
return select update while with << continue close current
delete fetch lock insert open rollback savepoint set sql execute
commit forall merge pipe purge json_exists json_value json_query
json_object json_array
And here is my code example:
CREATE OR REPLACE PROCEDURE PRINT_INFO
IS
BEGIN
INSERT INTO TABLE_T (TABLE_ID, MESSAGE) VALUES (1, 'Hello World!');
END PRINT_INFO;
/
CREATE OR REPLACE PROCEDURE CREATE_TABLE
IS
BEGIN
CREATE TABLE TABLE_T(
TABLE_ID NUMBER NOT NULL,
MESSAGE VARCHAR2(25),
PRIMARY KEY(TABLE_ID)
);
PRINT_INFO;
END CREATE_TABLE;
/
EXEC CREATE_TABLE;
Where could be the problem? How can I get rid of an exception?

Both procedures have to use dynamic SQL:
print_info because it inserts into a table which - at compilation time - doesn't exist yet
create_table because it runs DDL and - in order to do that - you need to use dynamic SQL
Therefore:
SQL> CREATE OR REPLACE PROCEDURE PRINT_INFO
2 IS
3 BEGIN
4 execute immediate q'[INSERT INTO TABLE_T (TABLE_ID, MESSAGE) VALUES (1, 'Hello World!')]';
5 END PRINT_INFO;
6 /
Procedure created.
SQL> CREATE OR REPLACE PROCEDURE CREATE_TABLE
2 IS
3 BEGIN
4 execute immediate 'CREATE TABLE TABLE_T(' ||
5 'TABLE_ID NUMBER NOT NULL, ' ||
6 ' MESSAGE VARCHAR2(25), ' ||
7 ' PRIMARY KEY(TABLE_ID) ' ||
8 ')';
9
10 PRINT_INFO;
11 END CREATE_TABLE;
12 /
Procedure created.
SQL> EXEC CREATE_TABLE;
PL/SQL procedure successfully completed.
SQL> SELECT * FROM table_t;
TABLE_ID MESSAGE
---------- -------------------------
1 Hello World!
SQL>

You have to declare a string and assign your ddl to that variable then use
execute immediate your_variable ;

Related

It is possible to modify data in loop from table which was created in previous procedure?

I'm learning to work with PL/SQL procedures. Now I am trying to create table TABLE_T in procedure CREATE_TABLE then I trying to insert data with procedure INSERT_DATA. Inserted data should be modified in procedure MODIFY_DATA.
So data after insertion should look like:
LINE_ID | LINE_MESSAGE
----------------------
1 | 'Hello'
2 | 'Hi'
3 | 'Ciao'
After modification, they should look like:
LINE_ID | LINE_MESSAGE
----------------------
1 | 'Hello world!'
2 | 'Hi world!'
3 | 'Ciao world!'
But the procedure MODIFY_DATA throwing an exception, because allegedly the table does not exist:
Errors: PROCEDURE MODIFY_DATA Line/Col: 4/17 PL/SQL: SQL Statement
ignored Line/Col: 4/51 PL/SQL: ORA-00942: table or view does not exist
Line/Col: 6/6 PL/SQL: Statement ignored Line/Col: 6/66 PLS-00364: loop
index variable 'REC' use is invalid
Errors: PROCEDURE INSERT_DATA Line/Col: 7/5 PL/SQL: Statement ignored
Errors: PROCEDURE CREATE_TABLE Line/Col: 8/5 PL/SQL: Statement ignored
And this is my code:
CREATE OR REPLACE PROCEDURE MODIFY_DATA
IS
BEGIN
FOR REC IN (SELECT LINE_ID, LINE_MESSAGE FROM TABLE_T)
LOOP
EXECUTE IMMEDIATE 'UPDATE TABLE_T SET LINE_MESSAGE = ''' || REC.LINE_MESSAGE || ' world!'' WHERE LINE_ID = ' || REC.LINE_ID;
END LOOP;
END MODIFY_DATA;
/
CREATE OR REPLACE PROCEDURE INSERT_DATA
IS
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO TABLE_T(LINE_ID, LINE_MESSAGE) VALUES (1, ''Hello'')';
EXECUTE IMMEDIATE 'INSERT INTO TABLE_T(LINE_ID, LINE_MESSAGE) VALUES (2, ''Hi'')';
EXECUTE IMMEDIATE 'INSERT INTO TABLE_T(LINE_ID, LINE_MESSAGE) VALUES (3, ''Ciao'')';
MODIFY_DATA;
END INSERT_DATA;
/
CREATE OR REPLACE PROCEDURE CREATE_TABLE
IS
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE TABLE_T ('
|| 'LINE_ID NUMBER NOT NULL,'
|| 'LINE_MESSAGE VARCHAR2(33) NOT NULL,'
|| 'PRIMARY KEY(LINE_ID))';
INSERT_DATA;
END CREATE_TABLE;
/
EXEC CREATE_TABLE;
How can I fix it?
As in your earlier question, table_t still doesn't exist when the modify_data procedure is created - which is what the error is telling you - so it can't be used in a static cursor.
but table is created with immediate command, so it should exist or no ?
It isn't created until the create_table procedure is executed; which is after modify_data is created. When you try to create that procedure the static line:
FOR REC IN (SELECT LINE_ID, LINE_MESSAGE FROM TABLE_T)
is trying to reference the table_t which doesn't yet exist. It doesn't matter that your code implies the execution order - from having create_table call insert_data, and that calling modify_data; which is unusual anyway, it might seem more natural to do this instead:
EXEC CREATE_TABLE;
EXEC INSERT_DATA;
EXEC MODIFY_DATA;
But either way, the problem is when you create modify_data, not when you execute.
You could use a dynamic cursor:
CREATE OR REPLACE PROCEDURE MODIFY_DATA
IS
CUR SYS_REFCURSOR;
TYPE REC_TYPE IS RECORD (
LINE_ID NUMBER,
LINE_MESSAGE VARCHAR2(33)
);
REC REC_TYPE;
BEGIN
OPEN CUR FOR 'SELECT LINE_ID, LINE_MESSAGE FROM TABLE_T';
LOOP
FETCH CUR INTO REC;
EXIT WHEN CUR%NOTFOUND;
EXECUTE IMMEDIATE 'UPDATE TABLE_T SET LINE_MESSAGE = ''' || REC.LINE_MESSAGE || ' world!'' WHERE LINE_ID = ' || REC.LINE_ID;
END LOOP;
CLOSE CUR;
END MODIFY_DATA;
/
db<>fiddle
check your code execution sequence:
EXEC CREATE_TABLE;
EXEC INSERT_DATA;
EXEC MODIFY_DATA;

stored procedure in oracle 11g

create procedure p5(age1 IN number) as
BEGIN
if age1>18 then
insert into t values ( age1 );
else
dbms_output.putline('age should be high');
end if;
end p5;
Warning: Procedure created with compilation errors.
I have tried executing this and i am getting errors listed below
SQL> exec p5(20);
BEGIN p5(20); END;
*
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00905: object SYSTEM.P5 is invalid
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
I am still getting these errors
There are multiple problems,
create or replace procedure p3(age1 IN number) as --you dont need (3) here. Also closing braces are missing.
BEGIN
if age1>18 then
insert into t values ( age1 );
else
dbms_output.put_line('age should be high'); --you were using putline.
end if;
end p3; --your proc name is p2 but you are endin p3. Not needed. Just END will also do.
I tried running it locally and it is working fine.
create table t (age number(3));
Table T created.
create procedure p3(age1 IN number) as
BEGIN
if age1>18 then
insert into t values ( age1 );
else
dbms_output.put_line('age should be high');
end if;
end p3;
Procedure P3 compiled
set serveroutput on;
exec p3(23);
PL/SQL procedure successfully completed.
exec p3(17);
PL/SQL procedure successfully completed.
age should be high
select * from t;
AGE
23
The error is here:
dbms_output.put_line
instead of
dbms_output.putline
You missed closing parenthesis after p3(age1 IN number(3). Try following :
create procedure p3(age1 IN number) as
BEGIN
if age1>18 then
insert into t values ( age1 );
else
dbms_output.put_line('age should be high'); -- it should be put_line
end if;
end p3; --correct procedure name

dynamic sql error ORA-00911

i have create the below simple code it will get table name dynamically and create a table as per the columns given in the input table
CREATE OR REPLACE
PROCEDURE dyn_sql_sp(
p_user VARCHAR2,
p_table_name VARCHAR2,
P_NW_tbl_name VARCHAR2)
AS
d_cols VARCHAR2(2000);
CURSOR col_c
IS
SELECT column_name
||' '
||data_type
||'('
||data_length
||')' colm
FROM All_Tab_Columns
WHERE owner =UPPER(p_user)
AND table_name=UPPER(p_table_name);
BEGIN
FOR i IN col_c
LOOP
d_cols:=d_cols||i.colm||',';
END LOOP;
D_Cols:=RTRIM(REPLACE(D_Cols,'DATE(7)','DATE'),',');
dbms_output.put_line( 'CREATE TABLE '||P_Nw_Tbl_Name||' ('||d_cols||');');
EXECUTE Immediate ' CREATE TABLE '||P_Nw_Tbl_Name||' ( '||d_cols||'); ';
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(sqlerrm||SQLCODE);
END;
but im getting error as
SQL> exec dyn_sql_sp('hr','departments','tamil');
CREATE TABLE tamil (DEPARTMENT_ID NUMBER(22),DEPARTMENT_NAME
VARCHAR2(30),MANAGER_ID NUMBER(22),LOCATION_ID NUMBER(22)
);
ORA-00911: invalid character
PL/SQL procedure successfully completed.
hope program is completely correct i can run the output separately and works fine but getting error while i dynamically create the same
SQL> CREATE TABLE tamil (DEPARTMENT_ID NUMBER(22),DEPARTMENT_NAME
2 VARCHAR2(30),MANAGER_ID NUMBER(22),LOCATION_ID NUMBER(22));
Table created.
The problem may be in the final ';' in the dynamic statement:
SQL> begin
2 execute immediate 'create table tab_one(a number);';
3 end;
4 /
begin
*
ERROR at line 1:
ORA-00911: invalid character
ORA-06512: at line 2
SQL> begin
2 execute immediate 'create table tab_one(a number)';
3 end;
4 /
PL/SQL procedure successfully completed.

INSERT after EXECUTE IMMEDIATE in oracle [duplicate]

I'm trying to create a table and then insert some values in it within the same procedure in pl/sql. I tried to run the following query without success:
create or replace Procedure insertval8(id_no in number,e_name in char)
is
begin
execute immediate 'create table edu2(id number(20), name char(12))';
insert into edu2 values(&id_no,&e_name);
end;
displays
LINE/COL ERROR
-------- -----------------------------------------------------------------
5/1 PL/SQL: SQL Statement ignored
5/13 PL/SQL: ORA-00942: table or view does not exists
The error persists until I remove the insert code.
The procedure cannot be compiled because the table is not present at compile time.
Wrap the insert in execute immediate also, or use a global temporary table (generaly the preferred solution for temporary data).
create or replace procedure insertval8 (id in number,
name in char )
is
begin
execute immediate 'create table edu2(id number(20), name char(12))';
execute immediate 'insert into edu2(id, name) values (:1, :2)'
using id, name;
end;

Incomplete/Malformed cursor

I have a PL/SQL script to perform some aggregation tasks. I am having compilation errors, logic is not top priority at this moment as that can be changed once the errors are resolved. The script is as follows :
SET SERVEROUTPUT ON;
ALTER SESSION SET NLS_DATE_FORMAT = 'dd-MON-yy';
CREATE OR REPLACE PROCEDURE updateFeaturePerformanceTable
(noOfDays IN NUMBER, runDate IN DATE, timeSpan IN VARCHAR2)
AS
CURSOR c_feature_performance IS
SELECT distinct mkt_id,dow,device_type,feature_name
FROM gfmdev.feature_performance
WHERE timespan = 'ONE_DAY'
AND feature_performance_day >= TO_DATE('17-AUG-15','dd-MON-yy');
rowsExtracted c_feature_performance%ROWTYPE;
extractDate DATE;
timespan_test varchar2(20);
BEGIN
OPEN c_feature_performance;
extractDate := runDate - noOfDays;
timespan_test := timeSpan;
LOOP
FETCH c_feature_performance INTO rowsExtracted;
EXIT WHEN c_feature_performance%NOTFOUND;
dbms_output.put_line(extractDate || ' ' || timespan_test);
INSERT INTO gfmdev.feature_performance
SELECT
rowsExtracted.mkt_id,
rowsExtracted.dow,
rowsExtracted.device_type,
rowsExtracted.feature_name,
SUM(OPS),
SUM(GV_COUNT),
runDate,
timespan_test
FROM gfmdev.feature_performance
WHERE feature_performance_day BETWEEN extractDate AND runDate
AND timespan = 'ONE_DAY'
AND mkt_id = rowsExtracted.mkt_id
AND dow = rowsExtracted.dow
AND device_type = rowsExtracted.device_type
AND feature_name = rowsExtracted.feature_name
group by mkt_id, dow, device_type, feature_name, timespan;
END LOOP;
CLOSE c_feature_performance;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
dbms_output.put_line('Trying to insert too many rows in SELECT...INTO');
ROLLBACK;
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('No rows returned in SELECT...INTO');
ROLLBACK;
WHEN STORAGE_ERROR THEN
dbms_output.put_line('Too much data to handle! Storage error');
ROLLBACK;
WHEN OTHERS THEN
dbms_output.put_line('Oops! Something went wrong');
ROLLBACK;
RAISE;
END updateFeaturePerformanceTable;
Show compilation errors:
SHOW ERRORS PROCEDURE updateFeaturePerformanceTable;
Run the procedure:
DECLARE
runDate DATE;
BEGIN
FOR j IN 0 .. 5 LOOP
SELECT (TO_DATE('17-AUG-15','dd-MON-yy') + j) INTO runDate FROM dual;
updateFeaturePerformanceTable(6,runDate, 'ONE_WEEK');
END LOOP;
DBMS_OUTPUT.PUT_LINE(' WEEKLY RECORDS UPDATED ');
FOR j IN 0 .. 28 LOOP
SELECT (TO_DATE('17-AUG-15','dd-MON-yy') + j) INTO runDate FROM dual;
updateFeaturePerformanceTable(29,runDate, 'ONE_MONTH');
END LOOP;
DBMS_OUTPUT.PUT_LINE(' MONTHLY RECORDS UPDATED ');
COMMIT;
END;
/
When I execute it I get the following error message :
Errors for PROCEDURE UPDATEFEATUREPERFORMANCETABLE:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/9 PLS-00341: declaration of cursor 'C_FEATURE_PERFORMANCE' is
incomplete or malformed
5/3 PL/SQL: SQL Statement ignored
6/15 PL/SQL: ORA-00942: table or view does not exist
8/16 PL/SQL: Item ignored
16/3 PL/SQL: SQL Statement ignored
16/36 PLS-00320: the declaration of the type of this expression is
incomplete or malformed
21/3 PL/SQL: SQL Statement ignored
LINE/COL ERROR
-------- -----------------------------------------------------------------
36/22 PL/SQL: ORA-00904: "ROWSEXTRACTED"."FEATURE_NAME": invalid
identifier
36/22 PLS-00320: the declaration of the type of this expression is
incomplete or malformed
updateFeaturePerformanceTable(6,runDate, 'ONE_WEEK');
*
Any help on where I am going wrong is highly appreciated?
PL/SQL is a framework for running SQL statements programmatically. So often we find that PL/SQL errors are caused by the SQL errors in our code.
That is the case here. You have several PL/SQL errors indicating that the Cursor declaration is invalid. And why is it invalid? This line holds the answer:
6/15 PL/SQL: ORA-00942: table or view does not exist
So the problem is, the owner of the procedure UPDATEFEATUREPERFORMANCETABLE (ugly name by the way) does not have rights on gfmdev.feature_performance.
To solve, the table owner GFMDEV needs to grant SELECT and INSERT directly to the account which owns this procedure.
SQL> conn gfmdev/password
SQL> grant select, insert on feature_performance to whoever;
Note that granting privileges through a view won't cut it. The Oracle security model only permits us to build objects - PL/SQL programs, views - with privileges granted directly to our user.