Select Variable in Oracle - oracle

Here is what I will do in TSQL
declare #Init_Cnt int =1,#Tot_cnt int
set #Tot_cnt = (select count(distinct column_name) from mytable)
while (#init_cnt <= #tot_cnt)
begin
//Insert statement
end
set #init_cnt = #init_cnt+1;
This is what I tried in Oracle
declare
v_Init_cnt INT;
v_Tot_cnt int;
set v_Init_cnt := 1;
begin
select count(distinct column_name) v_Tot_cnt into from mytable
end
begin
while v_Init_cnt
loop
dbms_output.put_line ('COUNT': || v_Init_cnt );
v_Init_cnt
exit when v_Init_cnt <= v_Tot_cnt ;
end loop;
end;
How will I achieve my Tsql version in Oracle? Am I doing it right? If I wanna select only my variable say
select v_Tot_cnt from dual; is not working how can I do that?

It would look something like this in Oracle.
DECLARE
v_Init_Cnt number(10) :=1;
v_Tot_cnt number(10);
BEGIN
select count(distinct column_name) INTO v_Tot_cnt from mytable;
WHILE (v_Init_Cnt <= v_Tot_cnt)
LOOP
--Insert statement
v_Init_Cnt := v_Init_Cnt+1;
END LOOP;
END;

Related

How assigne value from execute immediate into variable

--create table locations_localtab as select * from HR.locations;
SET SERVEROUTPUT ON;
declare
type tLOC_type is table of locations_localtab%rowtype index by binary_integer;
tLOC tLOC_type := tLOC_type();
vPostal_code locations_localtab.postal_code%type;
vCity locations_localtab.city%type;
vLocal varchar2(50);
vSource varchar2(50);
comm long;
begin
select location_id,null,postal_code,city,state_province,country_id
bulk collect into tLOC
from HR.locations;
for ii in (select column_name from (select 'POSTAL_CODE' c1,'CITY' c2, 'COUNTRY_ID' c3 from dual) UNPIVOT (column_name for (name_of_col) in (c1,c2,c3))) loop
for i in 1..tLOC.count loop
comm := 'vSource := tLOC('||i|| ').'||ii.column_name ;
dbms_output.put_line(comm);
execute immediate comm;
-- select city into vLocal from locations_localtab where location_id = tLOC(i).location_id;
dbms_output.put_line('vSOURCE -->'||'.'||vSOURCE);
dbms_output.put_line('vLOCAL -->'||'.'||vLOCAL);
end loop;
end loop;
-- output -->
-- vSource := tLOC(1).POSTAL_CODE;
-- vSource := tLOC(2).POSTAL_CODE;
I would like to make loop by column_name to use this iterator for another loop with table type..
I would like to assign value of tLOC(i).ii.column_name into variable vSource, how can I do this?
I have no idea how I can deal with it.
Thank you in advance for your help.

How to insert multiple row result of dynamic sql to another Table?

I write one dynamic SQL which the result of it is a table with 2 columns and multiple rows, I want to insert it to another table with 4 columns that 2 of them will be filled by the result of dynamic SQL, I try to use collection but don't know how to insert result to another table
CREATE OR REPLACE PROCEDURE P_C_SM_Failure_error_Code_P2P AS
v_month VARCHAR2(16); -- to get Month for each table
v_day VARCHAR2(16); -- to get day for each table
v_ERRCODE t_c_rpt_resultmsg.code%TYPE;
v_ERRMSG t_c_rpt_resultmsg.MESSAGE%TYPE;
v_param VARCHAR2(16);
v_sql VARCHAR2(3000);
v_result number;
type t_c_result is record (Err_code varchar2(2000), Err_count number);
type v_t_result is table of t_c_result index by PLS_INTEGER;
v_t1_result v_t_result;
BEGIN
v_sql :='0';
v_param := 'Gateway_G';
v_result := '0';
select to_char(sysdate - 1,'MM') into v_month from dual;
select to_char(sysdate - 1,'DD') into v_day from dual;
-- Get count of P2P
v_sql := '(select count(*), error_code from (
select error_code from sm_histable'||v_month||''||v_day||'#ORASMSC01 where
orgaccount = '''||v_param||''' and destaccount = '''||v_param||''' and
sm_status <> 1 union all
select error_code from sm_histable'||v_month||''||v_day||'#ORASMSC02 where
orgaccount = '''||v_param||''' and destaccount = '''||v_param||''' and
sm_status <> 1 )
group by error_code)';
EXECUTE IMMEDIATE v_sql bulk collect into v_t1_result;
--insert into t_c_rpt_result2 values (trunc(sysdate, 'DD'), v_errcount,
v_err_code,'Failure_error_Code_P2P');
--for indx in 1 .. v_t1_result.COUNT
--loop
--dbms_output.put_line (v_t1_result (indx).Err_code);
--end loop;
You may append the constant values of date and the error message to the subquery and run a dynamic insert. It should also work if you remove the outer parentheses of your dynamic sql since constants can be included in group by. Always remember to pass values as bind variables rather than concatenating them (v_param). Also, specify the column names explicitly in an INSERT statement.
v_sql := '(select count(*) as cnt, error_code
from (
select error_code from sm_histable'||v_month||''||v_day||'#ORASMSC01
where orgaccount = :x and destaccount = :x and sm_status <> 1
union all
select error_code from sm_histable'||v_month||''||v_day||'#ORASMSC02
where orgaccount = :x and destaccount = :x and sm_status <> 1 )
group by error_code)';
EXECUTE IMMEDIATE v_sql bulk collect into v_t1_result using v_param;
EXECUTE IMMEDIATE 'insert into t_c_rpt_result2(err_dt,err_msg,errcount,error_code)
select :dt,:msg,cnt,error_code from '|| v_sql
USING trunc(sysdate, 'DD'),'Failure_error_Code_P2P',v_param;
I think you are looking at an excellent use case for FORALL. The collection you are populating needs to be done with execute immediate since you are dynamically constructing the table name. But the insert into t_c_rpt_result2 looks static to me.
BEGIN
v_sql :=
'(select count(*) as cnt, error_code
from (
select error_code from sm_histable'
|| v_month
|| ''
|| v_day
|| '#ORASMSC01
where orgaccount = :x and destaccount = :x and sm_status <> 1
union all
select error_code from sm_histable'
|| v_month
|| ''
|| v_day
|| '#ORASMSC02
where orgaccount = :x and destaccount = :x and sm_status <> 1 )
group by error_code)';
EXECUTE IMMEDIATE v_sql BULK COLLECT INTO v_t1_result USING v_param;
FORALL indx IN 1 .. v_t1_result.COUNT
INSERT INTO t_c_rpt_result2 (err_dt,
err_msg,
errcount,
ERROR_CODE)
VALUES (TRUNC (SYSDATE, 'DD'),
'Failure_error_Code_P2P',
v_t1_result (indx).cnt,
v_t1_result (indx).ERROR_CODE);
END;
Find more examples of FORALL on LiveSQL here. Of course, even if your insert was dynamic, you can use FORALL - put the execute immediate directly "inside" the FORALL statement. But I don't think that complexity is justified here.
Hope that helps!

query to find all columns in a table with no value in it

I have written this query for finding the total number of column which does not have a value in a table but its not working.
SET serveroutput ON;
DECLARE
v_count NUMBER;
v_table_name VARCHAR2(200);
CURSOR c2
IS
SELECT Column_name FROM all_tab_columns WHERE table_name= A;
BEGIN
FOR r1 IN c2
LOOP
dbms_output.put_line(r1.column_name);
EXECUTE immediate('SELECT COUNT(r1.column_name) INTO v_count FROM HR'||'.'||A);
IF v_count =0 THEN
dbms_output.put_line(v_count);
END IF;
END LOOP;
END;
I would like you to try this code. It works for me :)
SET serveroutput ON;
DECLARE
myOwner VARCHAR2(20):='HR';
myTable VARCHAR2(25):='A';
CURSOR c2
IS
SELECT column_name,
avg_col_len
FROM all_tab_columns
WHERE table_name = myTable
AND owner = myOwner;
BEGIN
FOR r1 IN c2
LOOP
IF r1.AVG_COL_LEN =0 THEN
dbms_output.put_line('column_name = '||r1.column_name);
END IF;
END LOOP;
END;
Hope this can help you.

Can't Solve ora-06550 pls-00103 ERROR in Qyery

I wrote the following query to Update Table EMPSHIFT VALUES From SCHEDULEEMPLOYEES
Table but get the following Error ora-06550 pls-00103 and can't solve it
so what is the problem
DECLARE
day_date DATE:=TO_DATE('01/04/2017','DD/MM/YYYY');
BEGIN
LOOP
FOR employees IN (SELECT EmpID FROM EMPSHIFT)
LOOP
EXECUTE IMMEDIATE
' UPDATE EMPSHIFT SET EMPSHIFT."'||TO_CHAR(day_date)||'" =
(
SELECT SCHEDULEEMPLOYEES.SCHEDULEID ||'-'|| SCHEDULEEMPLOYEES.SHIFTS
FROM SCHEDULEEMPLOYEES INNER JOIN EMPSHIFT ON SCHEDULEEMPLOYEES.EMPLOYEEID = EMPSHIFT.EMPLOYEEID
WHERE SCHEDULEEMPLOYEES.DAYDATE = '||TO_CHAR(day_date)||' and EMPSHIFT.EMPLOYEEID = ' || employees.EmpID ||'
)
WHERE EMPSHIFT.EMPLOYEEID =' ||employees.EmpID ||';';
day_date = day_date + 1;
EXIT
WHEN day_date >TO_DATE('30/04/2017','DD/MM/YYYY');
END LOOP;
END LOOP;
END;
1) As others mentioned,"day_date = day_date + 1;" has missing the correct assignment operator ":=".
2) The "EXECUTE..." part is not required here. Why are You using it?
3) What is your goal? The current structure looks "weird". The first loop statement has no control of the flow, only the inner one has, but its loop iterations is only based on the employees count, not the dates.
4) Is the update statement correct? I mean the "set empshift.<..>. I doubt, he has an attribute named "01/04/2017".
Created an example,:
declare
l_day_date date:=to_date('01/04/2017','DD/MM/YYYY');
l_res varchar2(400);
begin
loop
for l_emp in (select emp_id from empshift_test_v)
loop
dbms_output.put_line('the emp_id is :'||l_emp.emp_id);
--update empshift_test_v etv
--set etv.empshift_code/*<correct_att_name>*/ = (
select
nvl((select
sct.sch_id ||'-'|| sct.shifts shift_code
from
SCHEDULEEMPLOYEES_TEST_V sct,
empshift_test_v etv1
where
sct.day_date = l_day_date and
sct.emp_id = etv1.emp_id and
etv1.emp_id = l_emp.emp_id),'no_info')
into
l_res
from
empshift_test_v etv
where
etv.emp_id = l_emp.emp_id;
dbms_output.put_line('day_date is :'||to_char(l_day_date,'DD/MM/YYYY'));
dbms_output.put_line('l_res is :'||l_res);
end loop;
l_day_date := l_day_date + 1;
exit when l_day_date >to_date('30/04/2017','DD/MM/YYYY');
end loop;
end;
WHERE views "EMPSHIFT_TEST_V" and "SCHEDULEEMPLOYEES_TEST_V" has info like:
enter image description here
Hope it helps.
UPDATE:
Modified it according to you data.
declare
l_day_date date:=to_date('01/04/2017','DD/MM/YYYY');
l_res number;
l_stmt varchar2(4000);
begin
loop
for l_emp in (select emp_id from empshift_test)
loop
dbms_output.put_line('the emp_id is :'||l_emp.emp_id);
begin
select
sct.shift
into
l_res
from
SCHEDULEEMPLOYEES_TEST sct,
empshift_test etv
where
sct.daydate = l_day_date and
sct.emp_id = etv.emp_id and
etv.emp_id = l_emp.emp_id;
exception
when NO_DATA_FOUND then
l_res := 0;
end;
dbms_output.put_line('day_date is :'||to_char(l_day_date,'DD/MM/YYYY'));
dbms_output.put_line('l_res is :'||l_res);
if l_res > 0 then
l_stmt := 'update empshift_test emp
set emp."'||to_char(l_day_date,'DD/MM/YYYY')||'" = '||l_res||'
where emp.emp_id = '||l_emp.emp_id||';';
dbms_output.put_line('l_stmt is :'||l_stmt);
execute immediate l_stmt;
end if;
end loop;
l_day_date := l_day_date + 1;
exit when l_day_date >to_date('30/04/2017','DD/MM/YYYY');
end loop;
end;
But there is a catch: if you run the DML statement manually - it works, but with execute immediate - it throws error ora-00933. He cant read the number column for some reason.
Another good stack question to solve:)
So the plan is:
1) Change the table structure; or
2) Solve the problem, when calling a attribute, named as number (with symbols like "/") using execute immediate.

compare xtable count with table in oracle procedure

(I have several tables and for each table I have corresponding xtable.
what I am trying to do is create oracle procedure that will compare counts between xtable and table,
if (xtable >= table)
do something...
type namesarray IS VARRAY(5) OF VARCHAR2(10);
tbl_names namesarray;
xtbl_names namesarray;
total integer;
BEGIN
tbl_names := namesarray('tbl1', 'tbl2', 'tbl3', 'tbl4');
xtbl_names := namesarray('xtbl1', 'xtbl2', 'xtbl3', 'xtbl4');
total := tbl_names.count;
FOR i in (
SELECT COUNT(*) as TBL_COUNTS FROM tbl_names(i);
SELECT COUNT(*) as XTBL_COUNTS FROM xtbl_names(i)
)
LOOP
IF(i.XTBL_COUNTS >= i.TBL_COUNTS )
THEN
-- print to console
END IF;
END LOOP;
END;
This is all I got so far.
Can someone help?
How about this?
if (xtable >= table)
do something...
type namesarray IS VARRAY(5) OF VARCHAR2(10);
tbl_names namesarray;
xtbl_names namesarray;
total integer;
v_count_1 integer;
v_count_2 integer;
BEGIN
tbl_names := namesarray('tbl1', 'tbl2', 'tbl3', 'tbl4');
xtbl_names := namesarray('xtbl1', 'xtbl2', 'xtbl3', 'xtbl4');
total := tbl_names.count;
FOR i in (
select
t1.table_name as tab_1_name, t2.table_name as tab_2_name
from ( select table_name from user_tables where table_name in (...) ) t1
,( select 'x'||table_name as table_name from user_tables where table_name in (...) ) t2
where 'x'||t1.table_name = t2.table_name
)
LOOP
execute immediate 'select count(*) from '||i.tab_1_name into v_count_1;
execute immediate 'select count(*) from '||i.tab_2_name into v_count_2;
IF( v_count_1 >= v_count_2 )
THEN
-- print to console
END IF;
END LOOP;
END;

Resources