DB2 Insert Into Temp Table in the middle of a script - insert

If I have several temp tables, and I want to insert data into one of them but then continue to create more temp tables is there a way to do that or do I need to break my query up.
This is an example of what I'd like to do
WITH A AS (SELECT Column1, Column2, Column3 FROM SomeTable WHERE SomeConditionA), -- Inital Temp Table
B AS(SELECT Column1, Column2, Column3 FROM SomeTable WHERE SomeConditionB), --Second Temp Table
INSERT INTO A SELECT * FROM B --Insert Table B into Table A
C AS(...), --Derives From A
D AS(...), --Derives From C
E AS(...) --Derives From D
SELECT * FROM E --Final Select Statement
Essentially my issue is that I don't know how to write the insert in a way that will allow me to continue creating more temp tables afterwards.
Thanks!

A Common Table Expression (CTE), WITH A AS (SELECT...) is not an actual temporary table, you can't insert into it.
It doesn't appear that you need to have a B since it's the same columns as selected in A, simply OR the conditions
WITH A AS (SELECT Column1, Column2, Column3
FROM SomeTable
WHERE SomeConditionA
or SomeConditionB),
C AS(...), --Derives From A
D AS(...), --Derives From C
E AS(...) --Derives From D
SELECT * FROM E --Final Select Statement
If B needed to select other columns or from another table, then UNION ALL (if duplicates are ok or not possible) or UNION (to remove any duplicate rows) the results.
WITH A AS (SELECT Column1, Column2, Column3
FROM SomeTable
WHERE SomeConditionA
UNION ALL
SELECT Column4, Column5, Column6
FROM SomeTable
WHERE SomeConditionB),
C AS(...), --Derives From A
D AS(...), --Derives From C
E AS(...) --Derives From D
SELECT * FROM E --Final Select Statement

Related

Oracle MINUS operator and delete

You can insert records into table B if they are in table A
insert into B
select * from A
minus
select * from B
How do you delete records that are in B and not in A?
select * from B
minus
select * from A
How to delete records?
The assumption is that we do not have a primary key or a unique one.
You can do it like this:
delete from a2
where (COLUMN1, COLUMN2, COLUMN3, ...) in (select * from a2
minus
select * from a1);
It works, but you have to enter the column names in the where clause. Can not do delete in such a beautiful way as insert into select * from ...?
If you wanted to continue with your current approach, you should not use select * in your minus query. Rather, you should always explicitly list out the columns which you want to use.
But, I would use an EXISTS query here:
DELETE
FROM tableB b
WHERE NOT EXISTS (SELECT 1 FROM tableA a
WHERE a.col1 = b.col1 AND
a.col2 = b.col2 AND
a.col3 = b.col3 AND ...);
Best practice going forward would to have a primary key column in the A table. Then, you would only need to check that column against the B table for uniqueness.

Oracle delete from tableA where a duplicate row is in tableB

As the title says, I am looking for a way to remove all rows from TableA where there is a matching row in TableB.
the Tables A & B have about 30 columns in them so a WHERE A.col1 = B.col1 etc would be a little problematical. Ideally I was hoping for something like
DELETE FROM tableA WHERE IN TableB
(overly simplified by this type of thing)
IN clause can compare all columns returned from select
DELETE FROM tableA WHERE ( col1,col2,col3,.. ) IN ( select col1,col2,col3... FROM TableB );
The brute force way to establish if two records from each table are the same is to just compare every column:
DELETE
FROM tableA a
WHERE EXISTS (SELECT 1 FROM tableB b WHERE a.col1 = b.col1 AND a.col2 = b.col2 AND ...
a.col30 = b.col30);
You could create function which checks structures of tables and, if they are the same, creates string containing correct conditions to compare.
For example here are two tables:
create table t1 (id, name, age) as (
select 1, 'Tom', 67 from dual union all
select 2, 'Tia', 42 from dual union all
select 3, 'Bob', 16 from dual );
create table t2 (id, name, age) as (
select 1, 'Tom', 51 from dual union all
select 3, 'Bob', 16 from dual );
Now use function:
select generate_condition('T1', 'T2') from dual;
result:
T1.ID = T2.ID and T1.NAME = T2.NAME and T1.AGE = T2.AGE
Copy this, paste and run delete query:
delete from t1 where exists (select 1 from t2 where <<PASTE_HERE>>)
Here is the function, adjust it if needed. I used user_tab_columns so if tables are on different schemas you need all_tab_columns and compare owners too. If you have Oracle 11g you can replace loop with listagg(). Second table has to contain all columns of first table and they have to be same type and length.
create or replace function generate_condition(i_t1 in varchar2, i_t2 in varchar2)
return varchar2 is
v varchar2(1000) := '';
begin
for rec in (select column_name, u2.column_id
from user_tab_cols u1
left join (select * from user_tab_cols where table_name = i_t2) u2
using (column_name, data_type, data_length)
where u1.table_name = i_t1 order by u1.column_id)
loop
if rec.column_id is null then
v := 'ERR: incompatible structures';
goto end_loop;
end if;
v := v||' and '||i_t1||'.'||rec.column_name
||' = '||i_t2||'.'||rec.column_name;
end loop;
<< end_loop >>
return(ltrim(v, ' and '));
end;
If you want to avoid running process manually you need dynamic PL/SQL.
create table tableA (a NUMBER, b VARCHAR2(5), c INTEGER);
create table tableB (a NUMBER, b VARCHAR2(5), c INTEGER);
As you said
WHERE A.col1 = B.col1 etc would be a little problematical
you could intersect the tables and mention all columns from tableA one time, like this:
delete tableA
where (a,b,c) in (select * from tableA
intersect
select * from tableB);

oracle insert into column using subquery

I want to insert data into a column in the table.
Table a
ID col1 col2
1 A null
2 B null
Table b
ID col1
1 C
2 D
Expected results:
Table A
ID col1 col2
1 A C
2 B D
I tried this:
insert into tableA (col2)
select b.col1
from tableB b , tableA a
where b.id = a.id
and I received
0 row inserted.
How do I insert the col1 in B into col2 in A for the matching 'id' columns?
Thank you.
You must use Merge statement when inserting based on joins.
Also in table tableA col2 already exist but you want to insert a value on join then you must update that column.
merge into tablea a
using tableb b
on (b.id = a.id)
when matched
then
update set a.col2 = b.col1;
What you want to do shouldn't require a subquery. I'm not a huge fan of the table a, table b notation, try this:
update a
set col2 = b.col1
from tableB b
join tableA a
on a.id = b.id

loop based on query result get error

I have the result of a first query, and then based on that result I want to join with other tables so I can select the fields in the query result and other tables.
I construct the following
BEGIN
FOR a_rec in (select col1, min(col2) as col2,col3 from a_tbl group by (col1, col3))
LOOP
select a_rec.col2, d_tbl.col4
from b_tbl b, c_tbl c, d_tbl d
where b.col1 = a_rec.col1 and c.col5 = b.col5 and d.col6 = c.col6;
END LOOP;
END;
then it reminds me that PLS-00428: an INTO clause is expected in this SELECT statement, so I create a temp table and the code becomes:
BEGIN
FOR a_rec in (select col1, min(col2) as col2,col3 from a_tbl group by (col1, col3))
LOOP
select a_rec.col2, d_tbl.col4 into tmp_tbl
from b_tbl b, c_tbl c, d_tbl d
where b.col1 = a_rec.col1 and c.col5 = b.col5 and d.col6 = c.col6;
END LOOP;
END;
then I get error like this PLS-00403: expression 'TMP_TBL' cannot be used as an INTO-target of a SELECT/FETCH statement
Maybe I should put the first query result into a temp table and then join it with other tables, although I wonder whether I can do it in such a procedure?
A SELECT INTO throws an error if the SELECT statement returns anything other than a single row. So that's clearly not what you want here. Since tmp_tbl is a global temporary table, you could do an INSERT SELECT in your loop
BEGIN
FOR a_rec in (select col1, min(col2) as col2,col3
from a_tbl
group by (col1, col3))
LOOP
INSERT INTO tmp_tbl( col2, col4 )
select a_rec.col2, d_tbl.col4
from b_tbl b,
c_tbl c,
d_tbl d
where b.col1 = a_rec.col1
and c.col5 = b.col5
and d.col6 = c.col6;
END LOOP;
END;
Since you say that you are just turning around and exporting the resulting data in SQL Developer, however, the temporary table doesn't seem particularly useful. You could remove all the PL/SQL and just write a single SELECT statement
select a.col2, d.col4
from (select col1, min(col2) as col2, col3
from a_tbl
group by col1, col3) a,
b_tbl b,
c_tbl c,
d_tbl d
where b.col1 = a.col1
and c.col5 = b.col5
and d.col6 = c.col6;

Self Join Oracle

I have a table table1 below is how the data looks like.
Column1 is my foreign key of another table.
Column1 Column2 Column3
1 A 06/MAY/14
1 A 05/MAY/14
1 B 06/MAY/14
1 B 01/JAN/00
1 A 01/JAN/00
Now i want to find distinct column1 values where it meets the following condition.
1.atleast one record where column2 should be A and column3 should be (sysdate - 1)
AND
2.atleast one record where column2 should be B and column3 should be (sysdate - 1)
Meaning alteast one A and B should have their column 3 populated with (sysdate - 1)
I have written the below query, please tell if i'm doing anything wrong.
I also want to know if i'm doing the right way of joining. The table contains around 50K records and performance should be fine i guess.
SELECT DISTINCT COLUMN1 FROM
TABLE1 A
JOIN
TABLE1 B ON (A.COLUMN1 = B.COLUMN1)
WHERE
((TRUNC(A.COLUMN3) - TRUNC(A.COLUMN3) = 0)
AND TRUNC(A.COLUMN3) = TRUNC(SYSDATE - 1)
AND TRUNC(B.COLUMN3) = TRUNC(SYSDATE - 1)
AND A.COLUMN2 = 'A'
AND B.COLUMN2 = 'B'
AND TO_CHAR(A.COLUMN3, 'DD-MON-YY') != '01-JAN-00'
AND TO_CHAR(B.COLUMN3, 'DD-MON-YY') != '01-JAN-00'
);
For performance-comparison one with subselects and group:
SELECT COLUMN1 FROM (
SELECT
COLUMN1,
COUNT(COLUMN2) CNT
FROM (
SELECT DISTINCT
COLUMN1,
COLUMN2
FROM TABLE1
WHERE TRUNCATE(COLUMN3) = SYSDATE - 1 AND
(COLUMN2 = 'A' OR COLUMN2 = 'B'))
GOUP BY COLUMN1)
WHERE CNT = 2
This should work
SELECT DISTINCT A.column1 -- Obtain distinct from A
FROM table1 A -- TableA
join table1 B -- TableB
ON A.column1 = B.column1 -- Joining them on Column1
WHERE A.column3 = SYSDATE - 1 -- Yesterdays data on Table A
AND A.column2 = 'A' -- A values
AND B.column2 = 'B'; -- B Values
Note: No distinctness in your test case. So try with a unique key.

Resources