oracle select from table if values not exists - oracle

I need to write oracle query (Just query)
to select values from table, and if not found select from another table.
any help to do this in pl/sql?

SELECT * FROM firstTable
UNION ALL
SELECT * FROM secondTable WHERE (SELECT count(*) FROM FIRST_TABLE ) = 0

You can enclose the SELECT statement within a block and add an exception handler to it.
So, if there are no rows selected from the first table, then you select from the second table. The structure would be something like below:
Begin
select <many columns> into <many variables or row type>
From Table1
where <conditions>;
EXCEPTION
WHEN NO_DATA_FOUND THEN
select <many columns> into <many variables or row type>
From Table2
Where <Conditions>;
End;
References:
Another related SO question
Exception Handlers
Documentation for the SELECT INTO statement

Here is an example of a PL/SQL function that will perform a test, and then execute a secondary query based upon the results of the test. You can adjust it to fit your needs:
set serveroutput on;
declare
row_count number;
column1 varchar(10);
column2 varchar(10);
column3 number;
begin
/*Perform your test*/
select count(target_column) into row_count
from my_table
where condition_column = 'x';
/*Run your secondary query based on the output of the first*/
if row_count > 0 then
select
col_x into column1,
col_y into column2,
col_z into column3
from my_other_table_A;
else
select
col_a into column1,
col_b into column2,
col_c into column3
from my_other_table_B;
end if;
/*Show the results*/
dbms_output.put_line('column1: ' || column1);
dbms_output.put_line('column2: ' || column2);
dbms_output.put_line('column3: ' || column3);
end;
/

Related

How to change alias to table name automatically in case of oracle?

We are currently analyzing hundreds of queries.
E.g
SELECT a.id,
a.name,
a.hobby,
b.desc
FROM tablename a,
table2 b
WHERE a.id = b.id;
or
SELECT id,
NAME,
hobby
FROM tablename;
above these can be change like below?
SELECT tablename.id,
tablename.name,
tablename.hobby,
table2.desc
FROM tablename tablename,
table2 table2
WHERE tablename.id = table2.id;
or
SELECT tablename.id,
tablename.name,
tablename.hobby
FROM tablename tablename;
Do you know any tools or methods that have the ability to change them?
Here is the Ananymous block for another query :
declare
v_query varchar2(4000) :='SELECT a.id,
a.name,
a.hobby,
b.desc
FROM tablename a,
table2 b
WHERE a.id = b.id';
tab_list varchar2(4000);
v_newquery varchar2(4000);
v_tab_alias varchar2(100);
v_tabname varchar2(500);
v_alias varchar2(40);
tab_cnt NUMBER :=0;
begin
-- table list
select replace(REGEXP_SUBSTR(regexp_replace(v_query,'FROM|WHERE','#'),'[^#]+',1,2)||chr(10),chr(10),null)
into tab_list
from dual;
-- no of tables
select REGEXP_COUNT(TRIM(REGEXP_SUBSTR(regexp_replace(v_query,'FROM|WHERE','#'),'[^#]+',1,2)),',')+1
into tab_cnt
from dual;
For i in 1..tab_cnt
LOOP
select TRIM(REGEXP_SUBSTR(tab_list,'[^,]+',1,i))
into v_tab_alias
from dual;
-- replace alias tablename for the column list
select TRIM(REGEXP_SUBSTR(v_tab_alias,'[^ ]+',1,1))
into v_tabname
from dual;
select TRIM(REGEXP_SUBSTR(v_tab_alias,'[^ ]+',1,2))
into v_alias
from dual;
select regexp_replace(v_query,v_alias||'\.',v_tabname||'.')
into v_newquery
from dual;
v_query:= v_newquery;
-- replace alias tablename in FROM clause
select regexp_replace(v_query,v_alias||'\,',v_tabname||',')
into v_query
from dual;
END LOOP;
-- replace alias last tablename before WHERE clause
select regexp_replace(v_query,v_tab_alias,v_tabname||' '||v_tabname)
into v_query
from dual;
DBMS_OUTPUT.PUT_LINE(v_query);
END;

Data not inserting to destination table

I have the following block of PL-SQL code in Oracle:
DECLARE TAB VARCHAR(100);
COL VARCHAR(100);
CURSOR C_COLS IS
select DISTINCT table_name, column_name
from all_tab_columns
where OWNER = 'MyDB' AND DATA_TYPE LIKE '%VARCHAR%';
BEGIN
OPEN C_COLS;
LOOP
FETCH C_COLS INTO TAB, COL;
EXIT WHEN C_COLS%notfound;
INSERT INTO TargetTable (TABLE_NAME, COLUMN_NAME, COLUMN_VALUE)
SELECT DISTINCT TAB,
COL,
(SELECT COL FROM TAB)
FROM TAB
WHERE REGEXP_LIKE(COL, '([ABCDEFGHIJKLMNOPQRSTUVWXYZ])\d\d\d\d\d\d([ABCDEFGHIJKLMNOPQRSTUVWXYZ])', 'ix');
END LOOP;
CLOSE C_COLS;
END;
The idea is to determine which tables in my rather large database contain a certain pattern of data and to find them.
So I want to return three columns: TableName, ColumnName, Value of ColumnName.
The above runs but returns no data and I can't understand why. The query in the cursor returns results, and if I hard code the table values into a simple select statement containing my Regex, I get results. I just want one result set that contains the thousands of results I expect.
Could it be the (SELECT COL FROM TAB) I'm using to dynamically find the column_value? I wasn't sure if I could express it this way.
If you want to select columns dynamically you may wish to try dynamic SQL.
DECLARE
w_sql VARCHAR2(32767);
BEGIN
DBMS_OUTPUT.enable(32767);
FOR s_cols IN (
select DISTINCT
table_name
, column_name
from all_tab_columns
where owner = 'MyDB'
AND data_type LIKE '%VARCHAR%'
)
LOOP
w_sql := q'!
INSERT
INTO TargetTable (TABLE_NAME, COLUMN_NAME, COLUMN_VALUE)
SELECT DISTINCT
':TAB'
, ':COL'
, :COL
FROM :TAB
WHERE REGEXP_LIKE(:COL, '([ABCDEFGHIJKLMNOPQRSTUVWXYZ])\d\d\d\d\d\d([ABCDEFGHIJKLMNOPQRSTUVWXYZ])', 'ix')
!';
w_sql := REPLACE(w_sql, ':TAB', s_cols.table_name);
w_sql := REPLACE(w_sql, ':COL', s_cols.column_name);
EXECUTE IMMEDIATE w_sql;
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line('Error for SQL :'|| w_sql ||'; error is :'|| SQLERRM);
END;

Get list of columns and alias name by a query string in Oracle

I'm using Pl/SQL with Oracle Database 11g.
I want to get a list of columns with alias by a query string.
There is a way to get all the column names of a query, using dbms_sql.describe_columns2 but only I get alias.
For example:
DECLARE
l_cursor NUMBER := dbms_sql.open_cursor;
l_ignore NUMBER;
l_desc dbms_sql.desc_tab2;
l_cnt NUMBER;
BEGIN
dbms_sql.parse( l_cursor, 'select a.col1 column1, a.col2 column2 from table_test a', dbms_sql.native );
dbms_sql.describe_columns2( l_cursor, l_cnt, l_desc );
FOR i IN 1 .. l_cnt LOOP
dbms_output.put_line(l_desc(i).col_name);
END LOOP;
dbms_sql.close_cursor( l_cursor );
END;
/
Returns:
column1
column2
Is there any way to get the values a.col1, or a.col2 with alias in the query?
The column names used in a SQL statement can be retrieved using Rob van Wijk's custom view DBA_DEPENDENCY_COLUMNS.
Install the view as SYS and grant select on dba_dependency_columns to <your user>;.
The view only works on objects. Create a VIEW on the SELECT statement and then the dependencies will be available. For example:
create table table_test(col1 number, col2 number);
create or replace view test_view as
select a.col1 column1, a.col2 column2 from table_test a;
select referenced_column
from sys.dba_dependency_columns
where owner = user
and name = 'TEST_VIEW'
order by 1;
Results:
REFERENCED_COLUMN
-----------------
COL1
COL2
The above results get the "list of columns". But part of your answer also implies you may want to get the "column expressions". That would be a completely different task, but is possible. Parsing SQL can be ridiculously difficult so it might help to explain exactly what you want and why you want it.

Setting the size of a varray to the result of a count SQL statement

I'm trying to store the result of a fairly simple select statement in a varray
select id from my_table where column1 is not null;
Ideally, I'd declare my varray and set its size to be
select count(id) from my_table where column1 is not null;
something like this pseudo-code:
type my_array_type is varray(select count(id) from my_table where column1 is not null) of int;
my_array my_array_type := my_array_type();
my_array.extend(select count(id) from my_table where column is not null);
FOR i IN 1..my_array.count LOOP
my_array(i) := <get id from select statement using cursor>;
END LOOP;
Is there a better approach to what I'm trying to achieve?
Dynamic size initialization with varray is not possible,you can try Nested table instead of it.
(By reference of Declare dynamic array in Oracle PL/SQL)
Please check sample code mentioned below.
DECLARE
type my_array_type is TABLE of MY_TABLE.COLUMN1%TYPE;
l_employees my_array_type;
BEGIN
-- All rows at once...
SELECT COLUMN1
BULK COLLECT INTO l_employees
FROM MY_TABLE
ORDER BY COLUMN1;
DBMS_OUTPUT.put_line (l_employees.COUNT);
FOR indx IN 1 .. l_employees.COUNT
LOOP
DBMS_OUTPUT.put_line (l_employees(indx));
END LOOP;
END;
Hope this will help you!

picking 1 column from 2 tables and comparing them

In my Oracle database there are two tables which are TEMP_HR and PAY_SLIP_APR_16. Both of them have a common column named EMP_ID. TEMP_HR has over 10,000 records and PAY_SLIP_APR_16 has around 6,000 records. I want to know how many EMP_ID of PAY_SLIP_APR_16 is matched with TEMP_HR. If any ID doesn't match then print it. And here is my simple approach but I think its a very bad approach. So any faster method?
DECLARE
INPUT_EMP_NO VARCHAR2(13 BYTE);
INPUT_EMP_ID VARCHAR2(13 BYTE);
ROW_COUNT_1 NUMBER(6,0);
ROW_COUNT_2 NUMBER(6,0);
MATCHED_ID NUMBER;
UNMATCHED_ID NUMBER;
BEGIN
ROW_COUNT_1:=0;
ROW_COUNT_2:=0;
MATCHED_ID:=0;
UNMATCHED_ID:=0;
SELECT COUNT(*) INTO ROW_COUNT_1 FROM PAY_SLIP_APR_16;
SELECT COUNT(*) INTO ROW_COUNT_2 FROM TEMP_HR;
FOR A IN 1..ROW_COUNT_1 LOOP
BEGIN
SELECT EMP_ID INTO INPUT_EMP_ID FROM (SELECT EMP_ID, ROWNUM AS RN FROM PAY_SLIP_APR_16) WHERE RN=A;
FOR B IN 1..ROW_COUNT_2 LOOP
SELECT EMP_NO INTO INPUT_EMP_NO FROM (SELECT EMP_NO, ROWNUM AS RON FROM TEMP_HR) WHERE RON=B;
IF(INPUT_EMP_ID=INPUT_EMP_NO)THEN
MATCHED_ID:=MATCHED_ID+1;
EXIT;
ELSE
CONTINUE;
END IF;
END LOOP;
UNMATCHED_ID:=UNMATCHED_ID+1;
DBMS_OUTPUT.PUT_LINE(INPUT_EMP_ID);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(INPUT_EMP_ID||' -> '||SQLERRM);
END;
END LOOP;
DBMS_OUTPUT.PUT_LINE('MATCHED -> '||MATCHED_ID);
DBMS_OUTPUT.PUT_LINE('UNMATCHED -> '||UNMATCHED_ID);
END;
Use an outer join filtering for missed joins:
select p.*
from PAY_SLIP_APR_16 p
left join TEMP_HR t on t.EMP_ID = p.EMP_ID
where t.EMP_ID is null
An index on TEMP_HR(EMP_ID) will make this query fly.
You should use SQL sets!
To check which EMP_ID isn't in TEMP_HR you may try this:
select EMP_ID FROM PAY_SLIP_APR_16
where EMP_ID not in (select EMP_NO from TEMP_HR);
Then the other way around:
select EMP_NO FROM TEMP_HR
where EMP_NO not in (select EMP_ID from PAY_SLIP_APR_16);

Resources