I got procedure where I want to insert value to variable from Col1:
Procedure insertX
IS
var1 varchar2(100) := '';
check_s1 : = 'select Col1 into '||var1||' from table1';
begin
EXECUTE IMMEDIATE check_s1;
if var1 is null then
...
else
...
end if;
end;
But when I execute it something goes wrong.
As I see select into had error.
How to insert the value to my Var1 and then use it in IF condition?
Wrong syntax. Should be
SQL> set serveroutput on
SQL> declare
2 var1 varchar2(100);
3 check_s1 varchar2(100) := 'select dummy from dual';
4 begin
5 execute immediate check_s1 into var1;
6
7 if var1 is null then
8 dbms_output.put_line('var1 is null');
9 else
10 dbms_output.put_line('var1 = ' || var1);
11 end if;
12 end;
13 /
var1 = X
PL/SQL procedure successfully completed.
SQL>
Related
I need to create an anonymous block which will calculate the number of rows in the table with the name and selection criterion determined at runtime.
This is my attempt:
DECLARE
tableName VARCHAR2(45) :=:numeTable;
col VARCHAR2(45):=:campul;
val VARCHAR2(30):=:idValue;
BEGIN
EXECUTE IMMEDIATE
'select count(*) from :tableName where :col = :val'
USING tableName, col, val;
END;
You can't bind table or column names; concatenate them (and beware of SQL injection).
SQL> declare
2 tablename varchar2(30) := 'emp';
3 col varchar2(30) := 'job';
4 val varchar2(30) := 'CLERK';
5 l_cnt number;
6 begin
7 execute immediate 'select count(*) from ' || dbms_assert.sql_object_name(tableName) ||
8 ' where ' || dbms_assert.simple_sql_name(col) || ' = :a'
9 into l_cnt
10 using val;
11
12 dbms_output.put_line('count = ' || l_cnt);
13 end;
14 /
count = 4
PL/SQL procedure successfully completed.
SQL>
I'm try to loop some tables and run select as below:
set serveroutput on
declare
type tables_names is table of varchar2(30);
type selectTable is table of varchar2(30);
tName tables_names;
sTableName selectTable;
begin;
tName := tables_names('PERIOD','SETTING','RAP','LOG');
sTableName := selectTable('m_table1','m_table2','m_table3','m_table4','m_table5');
for i in 1..tName.count loop
for j in 1..sTableName.count loop
select col10, count(*) from user.sTableName(j)
where table_name = tName(i) group by col10;
end loop;
end loop;
end;
I got error:PL/SQL: ORA-00933.
Can you please tell me how can I correctly run PL/SQL procedure to have displayed result from my select?
UPDATE: looking result
Normally, to get this I need to run below select's:
select column_name,
count(*) as countColumn
from user.m_table1 where table_name = 'PERIOD' group by column_name;
select column_name,
count(*) as countColumn
from user.m_table2 where table_name = 'PERIOD' group by column_name;
Oracle complains (ORA-00933) that command isn't properly ended. That's probably because of a semi-colon behind the BEGIN; also, you lack the INTO clause.
I'm not sure what PERIOD, SETTING, ... are opposed to m_table1, m_table2, ... Which ones of those are table names? What are those other values, then?
Anyway: here's an example which shows how to do something like that - counting rows from tables. Try to adjust it to your situation, or - possibly - add some more info so that we'd know what you are doing.
SQL> set serveroutput on
SQL> declare
2 tname sys.odcivarchar2list := sys.odcivarchar2list();
3 l_cnt number;
4 l_str varchar2(200);
5 begin
6 tname := sys.odcivarchar2list('EMP', 'DEPT');
7
8 for i in 1 .. tname.count loop
9 l_str := 'select count(*) from ' || tname(i);
10 execute immediate l_str into l_cnt;
11 dbms_output.put_line(tname(i) ||': '|| l_cnt);
12 end loop;
13 end;
14 /
EMP: 14
DEPT: 4
PL/SQL procedure successfully completed.
SQL>
[EDIT: added GROUP BY option]
Here you go; as EMP and DEPT share the DEPTNO column, I chose it for a GROUP BY column.
SQL> declare
2 tname sys.odcivarchar2list := sys.odcivarchar2list();
3 type t_job is record (deptno varchar2(20), cnt number);
4 type t_tjob is table of t_job;
5 l_tjob t_tjob := t_tjob();
6 l_str varchar2(200);
7 begin
8 tname := sys.odcivarchar2list('EMP', 'DEPT');
9
10 for i in 1 .. tname.count loop
11 l_str := 'select deptno, count(*) from ' || tname(i) ||' group by deptno';
12 execute immediate l_str bulk collect into l_tjob;
13
14 for j in l_tjob.first .. l_tjob.last loop
15 dbms_output.put_Line('Table ' || tname(i) || ': Deptno ' || l_tjob(j).deptno||
16 ': number of rows = '|| l_tjob(j).cnt);
17 end loop;
18
19 end loop;
20 end;
21 /
Table EMP: Deptno 30: number of rows = 6
Table EMP: Deptno 20: number of rows = 5
Table EMP: Deptno 10: number of rows = 3
Table DEPT: Deptno 10: number of rows = 1
Table DEPT: Deptno 20: number of rows = 1
Table DEPT: Deptno 30: number of rows = 1
Table DEPT: Deptno 40: number of rows = 1
PL/SQL procedure successfully completed.
SQL>
You are probably looking for something like this. Note that you can't run a simple select statement inside a PL/SQL without INTO clause. use a refcursor and DBMS_SQL.RETURN_RESULT
DECLARE
TYPE tables_names IS TABLE OF VARCHAR2 (30);
TYPE selectTable IS TABLE OF VARCHAR2 (30);
tName tables_names;
sTableName selectTable;
rc SYS_REFCURSOR;
BEGIN
tName :=
tables_names ('PERIOD',
'SETTING',
'RAP',
'LOG');
sTableName :=
selectTable ('m_table1',
'm_table2',
'm_table3',
'm_table4',
'm_table5');
FOR i IN 1 .. tName.COUNT
LOOP
FOR j IN 1 .. sTableName.COUNT
LOOP
OPEN rc FOR
'select col10, count(*) from '||USER||'.'
|| sTableName (j)
|| ' where table_name = '''
|| tName (i)
|| ''' group by col10';
DBMS_SQL.RETURN_RESULT (rc);
END LOOP;
END LOOP;
END;
/
I need to generate multiple columns from dual table. Number of columns to be generated gets decided by user input. If input is 3 then three times 'ABC'. If it is 4 then 4 times 'ABC' should be selected from dual.
I tried union all but I am trying to find out more efficient way of doing it.
DECLARE
v_value varchar2(10):='ABC'
v_count number:=3;
VAR varchar2(4000)
BEGIN
select 'ABC','ABC','ABC' INTO VAR FROM DUAL;
END;
Try this. Here you can input the number of times 'ABC' needed as column at runtime:
Code:
declare
user_input number := #
var varchar2(10) := '''ABC''';
var1 varchar2(2000);
v_sql varchar2(1000);
v_res varchar2(4000);
begin
var1 := var;
for i in 1 .. user_input - 1 loop
var1 := var1 || ',' || var;
end loop;
var1 := LTRIM(RTRIM(var1, ','), ',');
--dbms_output.put_line(var1);
v_sql := 'select :var1 from dual';
--dbms_output.put_line(v_sql);
Execute immediate v_sql
into v_res
using var1;
dbms_output.put_line(v_res);
end;
Demo:
SQL> declare
2
3 user_input number := #
4
5 var varchar2(10) := '''ABC''';
6 var1 varchar2(2000);
7 v_sql varchar2(1000);
8 v_res varchar2(4000);
9 begin
10
11 var1 := var;
12
13 for i in 1 .. user_input - 1 loop
14 var1 := var1 || ',' || var;
15 end loop;
16
17 var1 := LTRIM(RTRIM(var1, ','), ',');
18
19 --dbms_output.put_line(var1);
20
21 v_sql := 'select :var1 from dual';
22
23 --dbms_output.put_line(v_sql);
24
25 Execute immediate v_sql
26 into v_res
27 using var1;
28
29 dbms_output.put_line(v_res);
30
31 end;
32 /
Enter value for num: 2
old 3: user_input number := #
new 3: user_input number := 2;
'ABC','ABC'
PL/SQL procedure successfully completed.
SQL> /
Enter value for num: 5
old 3: user_input number := #
new 3: user_input number := 5;
'ABC','ABC','ABC','ABC','ABC'
PL/SQL procedure successfully completed.
SQL> /
Enter value for num: 7
old 3: user_input number := #
new 3: user_input number := 7;
'ABC','ABC','ABC','ABC','ABC','ABC','ABC'
PL/SQL procedure successfully completed.
SQL> /
Enter value for num: 6
old 3: user_input number := #
new 3: user_input number := 6;
'ABC','ABC','ABC','ABC','ABC','ABC'
PL/SQL procedure successfully completed.
SQL> /
Enter value for num: 9
old 3: user_input number := #
new 3: user_input number := 9;
'ABC','ABC','ABC','ABC','ABC','ABC','ABC','ABC','ABC'
PL/SQL procedure successfully completed.
Is that what you mean?
select RPAD('ABC',length('ABC')*3,'ABC') from dual
ABCABCABC
DECLARE
v_value varchar2(10):='ABC'
v_count number:=3;
VAR varchar2(4000)
BEGIN
select RPAD(v_value,length(v_value)*v_count,v_value) INTO VAR FROM DUAL;
END;
Your question is not that clear.
The fact that you are using a VARCHAR2(4000) variable for your result value makes me think that you need to get a single string composed by the concatenation of a string n times; if this is the case, you don't need a select ... from DUAL and can simply do:
DECLARE
v_value varchar2(10):='ABC';
v_count number:=4;
VAR varchar2(4000);
BEGIN
VAR := rpad(v_value, length(v_value) * v_count, v_value);
dbms_output.put_line(VAR);
END;
/
ABCABCABCABC
But you say you tried UNION, and this makes me think you need to get n rows with the same value; in this case, you may try:
DECLARE
type yourResultType is table of varchar2(10);
v_value varchar2(10):='ABC';
v_count number:=4;
VAR yourResultType;
BEGIN
select v_value
bulk collect into VAR
from dual
connect by level <= v_count;
--
for i in VAR.first .. VAR.last loop
dbms_output.put_line(VAR(i));
end loop;
END;
/
ABC
ABC
ABC
ABC
I have a script that creates a lot of tables, indexes, triggers etc. And I want to run all those DDLs conditionally. i tried to wrap the script with 'if then' but it didn't work
IF exists (select 1 from xxx where yyy) THEN
create table...
create table...
CREATE UNIQUE INDEX ...
CREATE TRIGGER ...
END IF;
how can i achieve that?
One of the ways:
begin
for cur in (select 1 from xxx where yyy and rownum <= 1) loop
execute immediate 'create table...';
execute immediate 'create table...';
execute immediate 'create unique index...';
end loop;
end;
/
P.S. One more way is to generate exception and proceed in SQL*Plus.
file example.sql:
SET ECHO OFF
SET VERIFY OFF
WHENEVER SQLERROR EXIT;
VAR x NUMBER
EXEC :x := &1
BEGIN
FOR cur IN (SELECT 1 FROM dual WHERE 1=:x) LOOP
RETURN;
END LOOP;
RAISE NO_DATA_FOUND;
END;
/
PROMPT Here we are
Result:
SQL> #example
Enter value for 1 1: 1
PL/SQL procedure completed.
PL/SQL procedure completed.
Here we are
SQL> #example
Enter value for 1: 2
PL/SQL procedure completed.
BEGIN
*
error in line 1:
ORA-01403: no data found
ORA-06512: in line 5
When I use value 2 the block raises exception and the script exists SQL*Plus.
P.S. One more example in response - hope this cleas questions below. I create table only when it does not exist. Table containts 1024 partitions and ' characters in DEFAULT statement. Text size > 32K.
SQL> set serveroutput on
SQL> DECLARE
2 sql_code clob;
3 delim varchar2(1) := '';
4 amount int;
5 sql_text varchar2(32767);
6 BEGIN
7
8 dbms_lob.createtemporary(sql_code,cache => true);
9 sql_text := q'[CREATE TABLE TEST_TAB (X INT PRIMARY KEY, Y VARCHAR2(10) DEFAULT 'DEF', Z INTEGER) PARTITION BY RANGE(Z) ( ]';
10 amount := length(sql_text);
11 dbms_lob.writeappend(sql_code,amount,sql_text);
12
13 for i in 1..1024 loop
14 sql_text := delim||'PARTITION P_'||i||' VALUES LESS THAN ('||i||')';
15 amount := length(sql_text);
16 dbms_lob.writeappend(sql_code,amount,sql_text);
17 delim := ',';
18 end loop;
19
20 dbms_lob.writeappend(sql_code,1,')');
21
22 FOR cur IN (
23 SELECT * FROM dual WHERE NOT EXISTS (
24 SELECT * FROM user_tables WHERE table_name = 'TEST_TAB')
25 ) LOOP
26 EXECUTE IMMEDIATE sql_code;
27 END LOOP;
28
29 dbms_output.put_line(dbms_lob.getlength(lob_loc => sql_code));
30
31 END;
32 /
39877
PL/SQL procedure completed.
SQL> desc test_tab
Имя Пусто? Тип
----------------------------------------- -------- ----------------------------
X NOT NULL NUMBER(38)
Y VARCHAR2(10)
Z NUMBER(38)
SQL> select count(*) from user_tab_partitions where table_name = 'TEST_TAB';
COUNT(*)
----------
1024
i' trying to create a SELECT in ORACLE .
i'm selecting from a table 3 columns
and i want to do a test (result of an other select)
if it's true show all columns
if false only show two.
create table t1(a int ,b int , c int) ;
select a , case when (1=1) then (b ,c)
else (b) end;
from t1 ;
It's not quite clear what you're trying to do.
If you're just interested in the result of this query, you can't do this. You can't have a query that returns an unknown number of columns. You could have three column and one be null unless your condition is met, like:
SELECT a, CASE WHEN ( condition ) THEN b ELSE NULL END AS b, c
FROM t1
If your goal is to actually create a table (but I would suggest strongly against doing table creation like this), you can use EXECUTE IMMEDIATE string, where string is a DDL command:
DECLARE
ddl VARCHAR2(4000);
BEGIN
IF (condition) THEN
ddl := 'CREATE TABLE t1 (a NUMBER, b NUMBER, c NUMBER )';
ELSE
ddl := 'CREATE TABLE t1 (a NUMBER, b NUMBER )';
END IF;
EXECUTE IMMEDIATE ddl;
END;
plsql with execute immediate is good decigin in your case. But if you want only data you may try like this, may be it's help you:
SELECT a,
CASE
WHEN (condition) THEN
b
ELSE
nvl(b, '') || ';' || nvl(c, '')
END AS NEW_COL
FROM t1
i.e. using pl/sql to open a cursor that selects columns dependant on a given input.
declare
v_select_all_cols boolean := true; --set as applicable.
v_rc sys_refcursor;
begin
if (v_select_all_cols)
then
open v_rc for select a,b,c from t1;
else
open v_rc for select a,b from t1;
end if;
-- now you can return the resultset v_rc to the caller
end;
/
e.g a quick test with sqlplus (ill use a var to print the cursor instead of a pl/sql variable)
SQL> var rc refcursor;
SQL> declare
2 v_select_all_cols boolean := true; --set as applicable.
3 begin
4
5 if (v_select_all_cols)
6 then
7 open :rc for select a,b,c from t1;
8 else
9 open :rc for select a,b from t1;
10 end if;
11 end;
12 /
PL/SQL procedure successfully completed.
SQL> print rc
A B C
---------- ---------- ----------
1 2 3
SQL> declare
2 v_select_all_cols boolean := false;
3 begin
4
5 if (v_select_all_cols)
6 then
7 open :rc for select a,b,c from t1;
8 else
9 open :rc for select a,b from t1;
10 end if;
11 end;
12 /
PL/SQL procedure successfully completed.
SQL> print rc
A B
---------- ----------
1 2