Getting the id for "No data found rows" in the Oracle - oracle

While querying for some of the ID in the table there are no rows.
How do I write pl/sql to get all those ID's
select type_id from table1 where pid = 123;
if type_id is null then
begin
DBMS_OUTPUT.put_line('Error ID'|| 123)
END
this doesn't work.

What is your datatype for typeid?
Assuming it is varchar2,
Try this:
DECLARE
v_type_id VARCHAR2(1000);
begin
select type_id INTO v_type_id from table1 where pid = 123;
DBMS_OUTPUT.put_line('Type Id is'|| v_type_id);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.put_line('Error ID'|| 123);
END

One way to accomplish this is to use an OUTER JOIN:
BEGIN
FOR aRow IN (SELECT p.PID
FROM PROCESSES p
LEFT OUTER JOIN TABLE1 t1
ON t1.PID = p.PID
WHERE p.PID = 123 AND
t1.TYPE_ID IS NULL)
LOOP
DBMS_OUTPUT.PUT_LINE('Error ID=' || aRow.PID);
END LOOP;
END;
Share and enjoy.

Related

Is there a way to make a PLSQL script that lists all columns that IS NULL for every record in a table?

I am working with a huge database with several columns and records. I want to browse a specific table and make a list of the columns that are empty for every record.
Is this possible without refering to all the specific column names?
Thanks for help!
It's possible but if you have a lot data it will last a long time.
create table xxx as select * from dba_objects where rownum < 10000;
prepare test table get table stats. It can be long lasting process.
begin
dbms_stats.gather_table_stats(user,'XXX',estimate_percent =>100);
-- ..
-- others tables to analizye
end;
Generate reports.
select table_name,column_name from user_tab_cols where coalesce(low_value,high_value) is null and table_name in('XXX');
You can use the below script to find out the null columns in your database -
DECLARE
COUNT_COL INT;
SQL_STR VARCHAR2(100);
BEGIN
FOR I IN (SELECT OBJECT_NAME, COLUMN_NAME
FROM USER_OBJECTS UO
JOIN USER_TAB_COLS UTC ON UO.OBJECT_NAME = UTC.TABLE_NAME) LOOP
SQL_STR := 'SELECT COUNT(1) FROM ' || I.OBJECT_NAME || ' WHERE ' || i.COLUMN_NAME || ' IS NOT NULL';
EXECUTE IMMEDIATE SQL_STR INTO COUNT_COL;
IF COUNT_COL = 0 THEN
DBMS_OUTPUT.PUT_LINE(I.COLUMN_NAME);
END IF;
END LOOP;
END;
Here is the fiddle.
Try for all record in table:
SELECT a.owner, a.table_name, b.column_name
FROM all_tables a, all_tab_columns b
WHERE a.table_name = '<TABLE_NAME>'
AND a.table_name = b.table_name
AND a.num_rows = b.num_nulls
For all table
SELECT a.owner, a.table_name, b.column_name
FROM all_tables a, all_tab_columns b
WHERE a.table_name = b.table_name
AND a.num_rows = b.num_nulls

How to get the number of rows in ROWTYPE variable

I have two tables Table1 an dTable2 that have identical columns. I need to check if a particular id is in one of them and return the row of data from whichever table.
I have the following PL/SQL code:
v_result Table1%ROWTYPE;
BEGIN
SELECT a.*
INTO v_result
FROM Table1 a
WHERE a.id = 123;
EXCEPTION
WHEN NO_DATA_FOUND THEN -- when record not found
SELECT b.*
INTO v_result
FROM Table2 b
WHERE b.id = 123;
END;
The issue is that the exception does not get thrown, so v_result returns no data. How can I check v_result for the number of rows?
For cursor I can use ROWCOUNT but v_result is not a cursor.
I also tried using count property but it errored out.
I changed my code to:
v_result Table1%ROWTYPE;
BEGIN
SELECT a.*
INTO v_result
FROM Table1 a
WHERE a.id = 123;
if v_result.count =0 then
SELECT b.*
INTO v_result
FROM Table2 b
WHERE b.id = 123;
end if;
EXCEPTION
WHEN NO_DATA_FOUND THEN -- when record not found
SELECT b.*
INTO v_result
FROM Table2 b
WHERE b.id = 123;
END;
And got an error component 'count' must be declared
What am I doing wrong?
You may use only a single row in a record variable. If you want to store and count multiple rows, you may define a collection of records and use BULK COLLECT INTO to load all of them at once and it won't raise a NO_DATA_FOUND. The count function works on collections.
DECLARE
TYPE type_tab1 IS TABLE OF Table1%ROWTYPE;
TYPE type_tab2 IS TABLE OF Table2%ROWTYPE;
v_result1 type_tab1;
v_result2 type_tab2;
BEGIN
SELECT a.*
BULK COLLECT INTO v_result1
FROM Table1 a
WHERE a.id = 123;
if v_result1.count = 0 then
SELECT b.* BULK COLLECT
INTO v_result2
FROM Table2 b
WHERE b.id = 123;
end if;
DBMS_OUTPUT.PUT_LINE('v_result1 ='|| v_result1.count);
DBMS_OUTPUT.PUT_LINE('v_result2 ='|| v_result2.count);
END;
/
Output for the Demo
v_result1 =0
v_result2 =1
If your intention is to simply check if a row exists, then a simpler and efficient approach would be to use EXISTS
SELECT
CASE WHEN
EXISTS (
SELECT 1
FROM table1
WHERE id = 123
) THEN 1
ELSE 0
END
INTO v_count
FROM dual;
IF v_count = 0
THEN
..
..

PL/SQL nested loop (loop within a loop)

Below is a PL/SQL I'm working on
declare
v_sql varchar2(500);
BEGIN
for t in (
SELECT distinct ID
FROM TABLEB
) loop
for c in (
select * from (
select 'delete from ' as test
from dual
union all
select 'TABLEA'||' where ' as test
from dual
union all
select 'ID='||t.ID
from dual
)
) loop
v_sql := v_sql || c.test;
end loop;
dbms_output.put_line(v_sql);
end loop;
END;
/
The result I'm getting is this
delete from TABLEA where ID=1
delete from TABLEA where ID=1delete from TABLEA where ID=2
I want
delete from TABLEA where ID=1
delete from TABLEA where ID=2
Any help on the PLSQL will be appreciated
What is the purpose of the inner FOR loop? It does nothing that requires a loop, and can be simply rewritten like this:
declare
v_sql varchar2(500);
begin
for t in (select distinct id from tableb) loop
v_sql := 'delete from tablea where id = ' || t.id ||';';
dbms_output.put_line(v_sql);
end loop;
end;
/
BTW, it seems that you're missing the terminating semicolon in line v_sql := ...
Demonstration on HR's DEPARTMENTS table:
SQL> declare
2 v_sql varchar2(500);
3 begin
4 for t in (select distinct department_id id from departments) loop
5 v_sql := 'delete from tablea where id = ' || t.id ||';';
6 dbms_output.put_line(v_sql);
7 end loop;
8 end;
9 /
delete from tablea where id = 10;
delete from tablea where id = 20;
delete from tablea where id = 30;
delete from tablea where id = 40;
delete from tablea where id = 50;
delete from tablea where id = 60;
<snip>
You're not clearing the buffer after you've printed the statement, so you're appending the next statement to the first one. To clear the buffer, add
v_sql := NULL;
after the line which reads
dbms_output.put_line(v_sql);
Best of luck.

oracle read column names from select statement

I wonder how read column names in oracle. Ok, I know that there is table named USER_TAB_COLUMNS which gives info about it, but if I have 2 or 3 level nested query and I don't know column names. Or I just have simple query with join statement and i want to get column names. How to do that? any idey?
select * from person a
join person_details b where a.person_id = b.person_id
thanks
I would go for:
select 'select ' || LISTAGG(column_name , ',') within group (order by column_id) || ' from T1'
from user_tab_columns
where table_name = 'T1';
to get a query from database. To get columns with types to fill map you can use just:
select column_name , data_type
from user_tab_columns
where table_name = 'T1';
I assume you are looking for this:
DECLARE
sqlStr VARCHAR2(1000);
cur INTEGER;
columnCount INTEGER;
describeColumns DBMS_SQL.DESC_TAB2;
BEGIN
sqlStr := 'SELECT a.*, b.*, SYSDATE as "Customized column name"
FROM person a JOIN person_details b
WHERE a.person_id = b.person_id';
cur := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(cur, sqlStr, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS2(cur, columnCount, describeColumns);
FOR i IN 1..columnCount LOOP
DBMS_OUTPUT.PUT_LINE ( describeColumns(i).COL_NAME );
END LOOP;
DBMS_SQL.CLOSE_CURSOR(cur);
END;

Insert within FORALL loop in PL/SQL

Is it possible to do something like this in pl/sql for bulk insert using FORALL?
TYPE c_type1 IS RECORD
(
column1 table1.column1%TYPE,
column2 table1.column2%TYPE,
client table2.client%TYPE
);
type1 c_type1;
CURSOR cur_t IS select * BULK COLLECT INTO recs from table3 ;
begin
FOR recs IN cur_t
LOOP
SELECT * INTO type1 FROM (select a.column1, a.column2,imm.client
...
from table1 a, table2 imm
WHERE
a.column1 = recs.column1
) WHERE ROWNUM=1;
INSERT INTO table2 values (recs.column1,type1.column2);
...
P.S : There are more 80 columns to be inserted.
Your question is not pretty clear but looking at your code I have the following. Check if this is what you were looking for.
declare
CURSOR cur_t IS
select t3.column1 , t1.column2
from table3 t3
inner join table1 t1
on t3.column1 = t1.column1;
type var_cur is table of cur_t%rowtype;
var var_cur;
begin
open cur_t;
LOOP
FETCH cur_t bulk collect into var limit 100;
EXIT WHEN cur_t%NOTFOUND;
FORALL i IN 1 .. var.count SAVE EXCEPTIONS
INSERT INTO TABLE2
VALUES var(i);
END LOOP;
CLOSE distinctUserIdCursor;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error in Insertion of record' || '~~~~' || SQLERRM);
FOR indx IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
DBMS_OUTPUT.put_line (SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX|| ': '
|| SQL%BULK_EXCEPTIONS (indx).ERROR_CODE);
END LOOP;
end;

Resources