Exclude columns from Minus operations in oracle sql - sql

I'd like to know if you can exclude a column from a MINUS operation
For example:
select column 1, column 2, column 3
from table 1
minus
select column 1, column 2
from table 2;
while column 3 is excluded from the operation.
Is there anyway to do that?
Thank you

You have a few alternatives.
#1
Minus without column3 then rejoin result to the original table to get the missing values for column3.
select *
from (
select column1, column2
from table1
minus
select column1, column2
from table2
)
join table1 using (column1, column2)
#2
Use an ANTI-JOIN the NOT EXISTS clause should work the same as NOT IN anyway.
select column1, column2, column3
from table1
where (column1, column2) not in (
select column1, column2
from table2
)

Perhaps you are after this?
select table1.column1, table1.column2, table1.column3
from table1
left table2 on table1.column1 = table2.column1 and table1.column2 = table2.column2
where table1.id IS NULL
This will result in only those table1 records that do not have matching column1 and column2 values in table2.

Look at this:
with t(a, b, c) as (
select 1, 2, 3 from dual union all
select 2, 2, null from dual union all
select 2, 3, 5 from dual
), t1(a, b) as (
select 1, 2 from dual union all
select 2, 2 from dual union all
select 2, 3 from dual
), t2 as (
select a, b, c from t
minus
select a, b, null from t1
)
select a, b from t2
A B
-----
1 2
2 3
SQLFiddle
If you have null values in your column3 and you want to escape them you can escape them like this:
with t(a, b, c) as (
select 1, 2, 3 from dual union all
select 2, 2, null from dual union all
select 2, 3, 5 from dual
), t1(a, b) as (
select 1, 2 from dual union all
select 2, 2 from dual union all
select 2, 3 from dual
), t3 as (
select a, b, nvl(c, -1) from t
minus
select a, b, null from t1
)
select a, b from t3
A B
-----
1 2
2 2
2 3
SQLFiddle

Related

How to join the table based on condition in join keys

I have Two table, and I want to join them, but the join key is depend on the condition. For example when table2 column2 value is not represented in table1 start values, I want to join the
on the next value. For example, table2 column2 value 9 is not in start value, and I want to merge on value 10 (next possible value) from start columns.
select * from table1 left join table2 on table2.column2=table1.start or
table2.column2=table1.start+1 or table2.column2=table1.start+2 .. until I find merge value from start columns
You can use the LAG analytic function to find the previous start in table1 and then join between the previous and current values:
SELECT t1.col1,
t1."START",
t2.*
FROM ( SELECT t.*,
LAG("START") OVER (ORDER BY "START") AS prev
FROM table1 t
) t1
LEFT OUTER JOIN table2 t2
ON ((t1.prev IS NULL OR t1.prev < t2.col2) AND t2.col2 <= t1."START")
Which, for the sample data:
CREATE TABLE table1 (col1, "START") AS
SELECT 'a', 10 FROM DUAL UNION ALL
SELECT 'v', 11 FROM DUAL UNION ALL
SELECT 'b', 13 FROM DUAL UNION ALL
SELECT 'r', 14 FROM DUAL;
CREATE TABLE table2 (col1, col2) AS
SELECT 'a', 9 FROM DUAL UNION ALL
SELECT 'q', 10 FROM DUAL UNION ALL
SELECT 's', 11 FROM DUAL UNION ALL
SELECT 'd', 13 FROM DUAL;
Outputs:
COL1
START
COL1
COL2
a
10
a
9
a
10
q
10
v
11
s
11
b
13
d
13
r
14
null
null
fiddle

How to convert single row data into a single column in oracle

I have a table like:
column1 column2 column3 column4
A B C D
wants to convert it as:
Column
A
B
C
D
Without using this union all in oracle:
select column1 as Column from dual
union all
select column2 as Column from dual
union all
select column3 as Column from dual
union all
select column4 as Column from dual
You can try to use unpivot
select v
from (
SELECT 'A' column1,'B' column2,'C' column3,'D' column4 from dual
) t
unpivot
(
v for val in (column1,column2,column3,column4)
) u;
sqlfiddle:https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=b2105e1010b332ce5b702eba7bfa7f2d

join 2 tables with SQL

I have to join 2 tables with SQL in a special way:
TABLE1 has the fields GROUP and MEMBER, TABLE2 has the fields GROUP and MASTER.
I have to build a new TABLE3 with the fields GROUP and ID by copying TABLE1 to TABLE3 and search TABLE2 if there is a GROUP from TABLE1 and if, copy GROUP and MASTER to TABLE3.
Example:
table1:
group member
1 a
1 b
1 c
2 x
3 y
table2:
group master
3 n
3 z
1 k
9 v
2 m
7 o
8 p
Expected result, table3:
group id
1 a from table1
1 b from table1
1 c from table1
1 k from table2
2 x from table1
2 m from table2
3 y from table1
3 z from table2
3 n from table2
I hope everything's clear.
So what is the SQL query?
Thanks, Hein
The first part (copy members) should be easy:
INSERT INTO table3 (group, id) SELECT group, member FROM table1;
Then You just copy the masters, that are in groups, that are already present in table1:
INSERT INTO table3 (group, id) SELECT group, master FROM table2 WHERE group IN (SELECT DISTINCT group FROM table1);
Try this out. Of course you need to INSERT the whole selection to your new table named Table3.
WITH TABLE1(GRP,MMBR) AS
(SELECT 1, 'a' FROM DUAL UNION ALL
SELECT 1, 'b' FROM DUAL UNION ALL
SELECT 1, 'c' FROM DUAL UNION ALL
SELECT 2, 'x' FROM DUAL UNION ALL
SELECT 3, 'y' FROM DUAL),
TABLE2(GRP,MSTR) AS
(SELECT 3, 'n' FROM DUAL UNION ALL
SELECT 3, 'z' FROM DUAL UNION ALL
SELECT 1, 'k' FROM DUAL UNION ALL
SELECT 9, 'v' FROM DUAL UNION ALL
SELECT 2, 'm' FROM DUAL UNION ALL
SELECT 7, 'o' FROM DUAL UNION ALL
SELECT 8, 'p' FROM DUAL)
SELECT * FROM (
SELECT GRP, MMBR ID FROM TABLE1
UNION --UNION ALL if you need duplicates
SELECT GRP, MSTR ID FROM TABLE2
WHERE TABLE2.GRP IN (SELECT GRP FROM TABLE1)
)
ORDER BY GRP, ID
You can do it using UNION ALL and 2 simple SELECT in an INSERT as follows:
INSERT INTO table3(group,id)
SELECT group,id FROM table1
UNION ALL
SELECT group,id FROM table2
SELECT * FROM table3;
And if you don't want duplicate values,try this using UNION instead of UNION ALL:
INSERT INTO table3(group,id)
SELECT group,id FROM table1
UNION
SELECT group,id FROM table2
SELECT * FROM table3;

Cannot figure out logic to update a table

I have below table.
TABLE: ABCD
B column have value 1 whenever there is a change in A column. Now I have to update the table like below. How can I do that?
You can do this using a correlated subquery:
update t
set b = (select sum(t2.b) from t t2 where t2.A <= t.A);
This is standard SQL and should work in either Oracle or Teradata.
Lets have a slightly more complicated example (where the changes in B are not correlated to the changes in A):
Oracle Setup:
CREATE TABLE ABCD( A, B ) AS
SELECT 1, 0 FROM DUAL UNION ALL
SELECT 1, 0 FROM DUAL UNION ALL
SELECT 1, 1 FROM DUAL UNION ALL
SELECT 2, 1 FROM DUAL UNION ALL
SELECT 2, 0 FROM DUAL UNION ALL
SELECT 3, 0 FROM DUAL UNION ALL
SELECT 3, 1 FROM DUAL UNION ALL
SELECT 3, 0 FROM DUAL;
Update:
UPDATE ABCD t1
SET b = (
SELECT sm
FROM (
SELECT ROWID AS id,
SUM( b ) OVER ( ORDER BY a, ROWNUM ) AS sm
FROM ABCD
) t2
WHERE t1.ROWID = t2.ID
);
Output:
SELECT * FROM ABCD;
A B
- -
1 0
1 0
1 1
2 2
2 2
3 2
3 3
3 3
(Note: This is an Oracle solution; I have no idea if it will or won't work in Teradata.)

How to find largest sequence of consecutive null values in a column

I want to get the maximum consecutive occurrence of null in a column as shown in the screenshot. As there is ID column also there in this table, ordering could be done based on it.
Like in this case, the output would be 4 as maximum 4 nulls are together.
SELECT * INTO #tmp FROM (Select 1 AS ID, 1 as lvl union all
Select 2, 1 union all
Select 3, Null union all
Select 4, Null union all
Select 5, 1 union all
Select 6, 1 union all
Select 7, Null union all
Select 8, Null union all
Select 9, Null union all
Select 10, Null union all
Select 11, 1 union all
Select 12, 1 union all
Select 13, 1 union all
Select 14, 1)x
SELECT * FROM #tmp
DROP TABLE #tmp
I just dont know from where to start, so any help would be appreciable.
Following the post at this link, I found the solution of my problem. The query giving correct result as 4 is:
SELECT TOP 1 COUNT(*)AS MaxNull
FROM
#tmp t
JOIN #tmp t2 ON t2.id <= t.id
WHERE NOT EXISTS(
SELECT 1
FROM #tmp t3
WHERE t3.id BETWEEN t2.id AND t.id
AND NOT t3.lvl IS NULL)
GROUP BY t.id
ORDER BY COUNT(*)DESC;