Oracle, Execute immediate Insert - oracle

I'm trying to insert random generating data into table, here's code"
begin
FOR x in 1..300 LOOP
Execute immediate 'insert into emp values ('||prac_seq.nextval||','''||'name'||x||''','||trunc(dbms_random.value(1,300))||');';
end loop;
/
table emp has 3 columns - id,name,idmgr;
above query in execute immediate statement looks like:
insert into emp values (13,'name25',193);
This block did not run. When I tried to run single execute immediate statement (f.e.
begin
Execute immediate 'insert into emp values ('||prac_seq.nextval||','''||'name23'','||trunc(dbms_random.value(1,300))||');'
end;
/
ORA gives me an error:
Execute immediate 'insert into emp values
('||prac_seq.nextval||','''||'name23'','||trunc(dbms_random.value(1,300))||');';
end; Error report: ORA-00911: invalid character ORA-06512: at line 3
00911. 00000 - "invalid character"
*Cause: identifiers may not start with any ASCII character other than
letters and numbers. $#_ are also allowed after the first
character. Identifiers enclosed by doublequotes may contain
any character other than a doublequote. Alternative quotes
(q'#...#') cannot use spaces, tabs, or carriage returns as
delimiters. For all other contexts, consult the SQL Language
Reference Manual.
*Action:
And why? Commas, quotes.. everything is checked and fine.

Why are you using execute immediate for this. Try connect by level.
select prac_seq.nextval, 'name'||level, trunc(dbms_random.value(1,300)) as rnd
from dual
connect by level <= 300;

Try remove ; from your dynamic query.

Related

Create Table in a Loop inside Stored Procedure Oracle SQL

I am attempting to create a Oracle stored procedure which creates partitioned tables based off of a table containing the table names and the column to be partitioned with. A separate PL/SQL block iterates through the table and calls the procedure with the table name and the column name.
Procedure:
create or replace PROCEDURE exec_multiple_table_create (
table_name IN VARCHAR2,
column_name IN VARCHAR2
) IS
stmt VARCHAR2(5000);
tablename VARCHAR2(50);
columnname VARCHAR2(50);
BEGIN
tablename := table_name;
columnname := column_name;
-- DBMS_OUTPUT.PUT_LINE(tablename);
-- DBMS_OUTPUT.PUT_LINE(columnname);
stmt := 'create table '
|| TABLENAME
|| '_temp as (select * from '
|| COLUMNNAME
|| ' where 1=2)';
EXECUTE IMMEDIATE stmt
USING IN table_name, column_name;
stmt := 'alter table '
|| tablename
|| '_temp modify partition by range('
|| columnname
|| ')
(PARTITION observations_past VALUES LESS THAN (TO_DATE(''20000101'',''YYYYMMDD'')),
PARTITION observations_CY_2000 VALUES LESS THAN (TO_DATE(''20010101'',''YYYYMMDD'')),
PARTITION observations_CY_2001 VALUES LESS THAN (TO_DATE(''20020101'',''YYYYMMDD'')),
PARTITION observations_CY_2002 VALUES LESS THAN (TO_DATE(''20030101'',''YYYYMMDD'')),
PARTITION observations_CY_2003 VALUES LESS THAN (TO_DATE(''20040101'',''YYYYMMDD'')),
PARTITION observations_CY_2004 VALUES LESS THAN (TO_DATE(''20050101'',''YYYYMMDD'')),
PARTITION observations_CY_2005 VALUES LESS THAN (TO_DATE(''20060101'',''YYYYMMDD'')),
PARTITION observations_CY_2006 VALUES LESS THAN (TO_DATE(''20070101'',''YYYYMMDD'')),
PARTITION observations_CY_2007 VALUES LESS THAN (TO_DATE(''20080101'',''YYYYMMDD'')),
PARTITION observations_CY_2008 VALUES LESS THAN (TO_DATE(''20090101'',''YYYYMMDD'')),
PARTITION observations_CY_2009 VALUES LESS THAN (TO_DATE(''20100101'',''YYYYMMDD'')),
PARTITION observations_CY_2010 VALUES LESS THAN (TO_DATE(''20110101'',''YYYYMMDD'')),
PARTITION observations_FUTURE VALUES LESS THAN ( MAXVALUE ) )';
EXECUTE IMMEDIATE stmt
USING IN table_name, column_name;
RETURN;
END exec_multiple_table_create;
The PL/SQL block which is using the stored proc is:
BEGIN
FOR partition_item IN (
SELECT
table_name,
partition_column
FROM
partition_table
) LOOP
exec_multiple_table_create(partition_item.table_name, partition_item.partition_column);
END LOOP;
END;
Now, when I try executing the thing, this is what I am seeing:
Error report -
ORA-06550: line 9, column 9:
PLS-00905: object SCG_MYACCT_CUSTOMPC.EXEC_MULTIPLE_TABLE_CREATE is invalid
ORA-06550: line 9, column 9:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
I have a feeling that I am missing something. Please let me know what it is. The table containing the reference data exists and contains data.
I have tried refreshing the table, rewriting and modifying the pl/sql block & the procedure code. Nothing seems to be working.
Thanks in advance.
UPDATE 1:
There was a glitch in the stored procedure where I needed to refer to the tablename rather than the columnname in the code above. However, I am getting a different error right now.
Error report -
ORA-06546: DDL statement is executed in an illegal context
ORA-06512: at "SCG_MYACCT_CUSTOMPC.EXEC_MULTIPLE_TABLE_CREATE", line 18
ORA-06512: at line 9
ORA-06512: at line 9
06546. 00000 - "DDL statement is executed in an illegal context"
*Cause: DDL statement is executed dynamically in illegal PL/SQL context.
- Dynamic OPEN cursor for a DDL in PL/SQL
- Bind variable's used in USING clause to EXECUTE IMMEDIATE a DDL
- Define variable's used in INTO clause to EXECUTE IMMEDIATE a DDL
*Action: Use EXECUTE IMMEDIATE without USING and INTO clauses to execute
the DDL statement.
Please help me out with this as well.
UPDATE 2:
I removed the USING part of the EXECUTE IMMEDIATE statement. That seemed to take care of the error I posted. Getting a different error with versions now:
Error starting at line : 1 in command -
BEGIN
FOR partition_item IN (
SELECT
table_name,
partition_column
FROM
partition_table
) LOOP
exec_multiple_table_create(partition_item.table_name, partition_item.partition_column);
END LOOP;
END;
Error report -
ORA-00406: COMPATIBLE parameter needs to be 12.2.0.0.0 or greater
ORA-00722: Feature "Conversion into partitioned table"
ORA-06512: at "SCG_MYACCT_CUSTOMPC.EXEC_MULTIPLE_TABLE_CREATE", line 37
ORA-06512: at line 9
ORA-06512: at line 9
00406. 00000 - "COMPATIBLE parameter needs to be %s or greater"
*Cause: The COMPATIBLE initialization parameter is not high
enough to allow the operation. Allowing the command would make
the database incompatible with the release specified by the
current COMPATIBLE parameter.
*Action: Shutdown and startup with a higher compatibility setting.

PL/SQL Concatenation

i have a procedure that have in entry two parameters
CREATE_PARTITION( yearSource IN VARCHAR2 , yearDestination IN VARCHAR2 )
when i want to insert the yearSource concatenated with another string , nothing is inserted in the table
i declare the variable yearAA which take the yearSource and i concatenate it with a 'AA'
yearAA varchar2(30) := yearSource||'AA';
to insert it i use :
execute immediate ' INSERT INTO MOUADTEST2018 VALUES('||yearAA||')';
result : Nothing inserted
and it shows this message ORA-00984: column not allowed here
You have to quote the value. As it is, if yearAA is 2018AA, your code gets interpreted as:
execute immediate 'INSERT INTO MOUADTEST2018 VALUES(2018AA)';
Which tries to run
INSERT INTO MOUADTEST2018 VALUES(2018AA)
Which throws an error because 2018AA isn't in quotes, so Oracle thinks it must be an identifier (like a column name).
You could change your code to
execute immediate 'INSERT INTO MOUADTEST2018 VALUES('''||yearAA||''')';
But this isn't a best practice, since it allows SQL injection. Instead, use bind variables.
execute immediate 'INSERT INTO MOUADTEST2018 VALUES(:1)' using yearAA;
Also, I don't think you need execute immediate, so you can just do:
insert into MOUADTEST2018 values(yearAA);

Parameters wrong assignment (PL/SQL, ORACLE)

I'm trying to run below pl/sql block but I'm getting error:
set serveroutput on
declare
rowBefore VARCHAR2(32000);
myschema VARCHAR2(32000) := 'abc';
mytable VARCHAR2(32000) := 'table1';
param1 VARCHAR2(32000) := 'Tom';
begin
select count(*) into rowBefore from myschema.mytable where colA = param1;
--select count(*) into rowBefore from abc.table1 where colA = 'Tom';
DBMS_OUTPUT.PUT_LINE(rowBefore);
End;
How to correctly use my all parameters into select statement?
Update error:
Error report -
ORA-06550: linia 7, kolumna 50:
PL/SQL: ORA-00942: tabela lub perspektywa nie istnieje
ORA-06550: linia 7, kolumna 5:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
You can't use a variable as an identifier in a SQL statement. It is looking for a table that is actually called mytable - not one with the value of the variable with that name as you expect. And the same for the schema.
From the documentation:
If the statement is a SELECT statement, the PL/SQL compiler removes the INTO clause.
The PL/SQL compiler sends the statement to the SQL subsystem.
The SQL subsystem checks the syntax of the statement.
If the syntax is incorrect, the compilation of the PL/SQL unit fails. If the syntax is correct, the SQL subsystem determines the names of the tables and tries to resolve the other names in the scope of the SQL statement.
...
It tries to resolve other names, e.g. functions; but table names (and schema names, and column names) have to be valid to the SQL parser.
You have to use dynamic SQL to create a string that contains the statement, concatenating in the identifiers:
execute immediate 'select count(*) from ' || myschema ||'.'|| mytable
|| ' where colA = :value'
into rowBefore using param1;
If you print out that generated statement with dbms_output you should see it matching the commented-out version, except for the use of a bind variable for the columns value. That would also help highlight any errors - like not including whitespace between the concatenated parts of the statement, which is a common and easy mistake.
It's often a good idea to build the statement as a string variable to make such debugging easier:
declare
...
v_stmt varchar2(4000):
begin
v_stmt := 'select count(*) from ' || myschema ||'.'|| mytable
|| ' where colA = :value';
-- for debugging
dbms_output.put_line(v_stmt);
-- and run it
execute immediate vStmt into rowBefore using param1;
...
If you are really getting the identifiers passed in by a user or client you should validate them to avoid unexpected errors and SQL injection attacks. Also, if the identifiers might be case sensitive (i.e. schemas/tables created with quoted identifiers) then you may need to add double-quotes to the generated statement, and make sure the variables are the correct case.
error is ORA-942: table or view does not exists. run first below query and see if error still occurs.
-- should you use abc.table1, instead of myschema.mytable?
select count(*) rowBefore from myschema.mytable where colA = 'a';
if there is still error, then fix the SELECT statement first before you use it in the PL/SQL block.

executing `EXECUTE IMMEDIATE ` Oracle Statement Getting Error

I am NewBie to Oracle. When I Execute Following Statement
BEGIN
EXECUTE IMMEDIATE 'SELECT * FROM DUAL;';
END;
/
I Got Error as
Error starting at line : 2 in command - BEGIN EXECUTE IMMEDIATE
'SELECT * FROM DUAL;'; END;
Error report - ORA-00911: invalid
character ORA-06512: at line 2
00911. 00000 - "invalid character"
*Cause: identifiers may not start with any ASCII character other than
letters and numbers. $#_ are also allowed after the first
character. Identifiers enclosed by doublequotes may contain
any character other than a doublequote. Alternative quotes
(q'#...#') cannot use spaces, tabs, or carriage returns as
delimiters. For all other contexts, consult the SQL Language
Reference Manual.
*Action:
The problem is the ; character in 'SELECT * FROM DUAL;'.
From documentation:
execute_immediate_statement ::=
EXECUTE_IMMEDIATE dynamic_string
{
INTO { define_variable [, define_variable ...] | record_name }
| BULK COLLECT INTO { collection_name [, collection_name ...] | :host_array_name }
}
[ USING [ IN | OUT | IN OUT ] bind_argument
[, [ IN | OUT | IN OUT ] bind_argument] ... ] [ returning_clause ] ;
... where dynamic_string is (emphasis mine):
A string literal, variable, or expression that represents a single SQL
statement or a PL/SQL block. It must be of type CHAR or VARCHAR2, not
NCHAR or NVARCHAR2.
Since it won't accept multiple statements unless you enclose them in a single PL/SQL block, the ; separator is not expected.
There's a better explanation at Using the EXECUTE IMMEDIATE Statement in PL/SQL:
When constructing a single SQL statement in a dynamic string, do not
include a semicolon (;) at the end inside the quotation mark. When
constructing a PL/SQL anonymous block, include the semicolon at the
end of each PL/SQL statement and at the end of the anonymous block;
there will be a semicolon immediately before the end of the string
literal, and another following the closing single quotation mark.
you can fix the error by removing ; from the dynamic query.
BEGIN
EXECUTE IMMEDIATE 'SELECT * FROM DUAL';
END;
/
This query is not going to return any results;
select statement in EXECUTE IMMEDIATE without into clause will be ignored.
Declare
v_variable number;--some variable
BEGIN
EXECUTE IMMEDIATE 'SELECT clmn FROM tbl' into v_variable;
END;
/
Just remove ';' from the dymanic string.Try this :
BEGIN
EXECUTE IMMEDIATE 'SELECT * FROM DUAL';
END;

Oracle Cast using %TYPE attribute

I want to cast a value using %TYPE attribute in my SQL statement. The %TYPE attribute lets you use the datatype of a field, record, nested table, database column, or variable in your own declarations, rather than hardcoding the type names.
This works:
insert into t1 select cast(v as varchar2(1)) from t2;
But I would like to
insert into t1 select cast(v as t1.v%TYPE) from t2;
Error starting at line 16 in command:
insert into t1 select cast(v as t1.v%TYPE) from t2
Error at Command Line:16 Column:37
Error report:
SQL Error: ORA-00911: Ongeldig teken.
00911. 00000 - "invalid character"
*Cause: identifiers may not start with any ASCII character other than
letters and numbers. $#_ are also allowed after the first
character. Identifiers enclosed by doublequotes may contain
any character other than a doublequote. Alternative quotes
(q'#...#') cannot use spaces, tabs, or carriage returns as
delimiters. For all other contexts, consult the SQL Language
Reference Manual.
*Action:
Can this (or something similar) be done?
EDIT:
What I'm trying to achieve is: when t2.v is to large I want to truncate it. I'm trying to avoid using substr with a hard coded field length. So cast(v as t1.v%TYPE) instead of substr(v,1,1)
%TYPE is only available in PL/SQL, and can only be used in the declaration section of a block. So, you can't do what you're attempting.
You might think you could declare your own PL/SQL (sub)type and use that in the statement:
declare
subtype my_type is t1.v%type;
begin
insert into t1 select cast(v as my_type) from t2;
end;
/
... but that also won't work, because cast() is an SQL function not a PL/SQL one, and only recognises built-in and schema-level collection types; and you can't create an SQL type using the %TYPE either.
As a nasty hack, you could do something like:
insert into t1 select substr(v, 1,
select data_length
from user_tab_columns
where table_name = 'T1'
and column_name = 'V') from t2;
Which would be slightly more palatable if you could have that length stored in a variable - a substitution or bind variable in SQL*Plus, or a local variable in PL/SQL. For example, if it's a straight SQL update through SQL*Plus you could use a bind variable:
var t1_v_len number;
begin
select data_length into :t1_v_len
from user_tab_columns
where table_name = 'T1' and column_name = 'V';
end;
/
insert into t1 select substr(v, 1, :t1_v_len) from t2;
Something similar could be done in other set-ups, it depends where the insert is being performed.

Resources