Join Multiple tables based on value in one table - oracle

I have 3 Tables which I would like to join with Table_A based on the condition in Table_A as follows:
When value in DATA_1 column of Table_A has a value "aaa", I would like to join it with data in Table1, if "bbb", I would like to join it with data in Table2.
Table_A
ID DATA_1 DATA2
------------------
1x aaa qwe
2q bbb axz
3w ccc qws
4b aaa dal
5a ddd qws
Table_1
ID DATA_1 DATA_2 DATA_Y
--------------------------
1x aaa qwe wer
Table_2
ID DATA_1 DATA_X DATA_Y
---------------------------
1x bbb qwe wez
and so on..
What I have so far:
SELECT h.id,
h.data_1,
h.data_2,
a.data_x,
a.data_y
FROM table_a h,
table_1 a
WHERE h.order_id = a.order_id
UNION
SELECT h.id,
h.data_1,
h.data_2,
b.data_x,
b.data_y
FROM table_a h,
table_2 b
WHERE h.order_id = b.order_id
Instead of doing a union, is there a way to combine everything into one query?

Something like this, perhaps? Join + CASE. See lines #17 onward.
SQL> with
2 -- sample data
3 table_a (id, datat, data2) as
4 (select '1x', 'aaa', 'qwe' from dual union all
5 select '2q', 'bbb', 'axz' from dual union all
6 select '3w', 'ccc', 'qws' from dual
7 ),
8 table_1 (id, datat, datax, datay) as
9 (select '1x', 'aaa', 'tab1 qwe', 'wer' from dual union all
10 select '2q', 'bbb', 'tab1 xxx', 'bab' from dual
11 ),
12 table_2 (id, datat, datax, datay) as
13 (select '1x', 'aaa', 'tab2 qwe', 'wez' from dual union all
14 select '2q', 'bbb', 'tab2 yyy', 'fdf' from dual
15 )
16 -- query which might help
17 select h.id, h.datat, h.data2,
18 case when h.datat = 'aaa' then a.datax
19 when h.datat = 'bbb' then b.datax
20 end datax,
21 --
22 case when h.datat = 'aaa' then a.datay
23 when h.datat = 'bbb' then b.datay
24 end datay
25 from table_a h join table_1 a on a.id = h.id
26 join table_2 b on b.id = h.id;
ID DAT DAT DATAX DAT
-- --- --- -------- ---
1x aaa qwe tab1 qwe wer
2q bbb axz tab2 yyy fdf
SQL>

Related

join table with itself to create more row

me has a table which has following data in TABLE1
me wanted to make sure all teh name has all "work type" available for all those dates only which is in teh data. Output should like TABLE2
me tried to put a query like
select t1.name,t1.date,mt.work_type,t1.minutes
from table1 t1
right join (select distinct work_type from t1) mt on t1.work_type=mt.work_type
however it didn't work. Please halp
You need to join with a subquery that cross joins all the names, dates and work types.
SELECT mt.name, mt.date, mt.work_type, COALESCE(t1.minutes, 0) AS minutes
FROM (
SELECT DISTINCT t1.name, t1.date, t2.work_type
FROM table1 AS t1
CROSS JOIN table1 AS t2
) AS mt
LEFT JOIN table1 AS t1
ON t1.name = mt.name AND t1.date = mt.date AND t1.work_type = mt.work_type
ORDER BY mt.name, mt.date, mt.work_type
Note that in the subquery you have to specify the actual table name, not the alias from the main query.
DEMO
In Oracle, you can use a partitioned outer join:
SELECT t.name,
t."DATE",
w.work_type,
COALESCE(t.minutes, 0) AS minutes
FROM (SELECT DISTINCT work_type FROM table1) w
LEFT OUTER JOIN table1 t
PARTITION BY (t.name, t."DATE")
ON (w.work_type = t.work_type)
Which, for the sample data:
CREATE TABLE table1 (name, "DATE", work_type, minutes) AS
SELECT 'a', DATE '2011-01-01', 'labor', 53 FROM DUAL UNION ALL
SELECT 'a', DATE '2011-01-01', 'private', 58 FROM DUAL UNION ALL
SELECT 'a', DATE '2011-01-01', 'other', 19 FROM DUAL UNION ALL
SELECT 'b', DATE '2011-01-02', 'labor', 31 FROM DUAL UNION ALL
SELECT 'b', DATE '2011-01-02', 'other', 24 FROM DUAL UNION ALL
SELECT 'b', DATE '2011-01-01', 'private', 19 FROM DUAL UNION ALL
SELECT 'c', DATE '2011-01-03', 'labor', 25 FROM DUAL UNION ALL
SELECT 'c', DATE '2011-01-03', 'private', 50 FROM DUAL UNION ALL
SELECT 'c', DATE '2011-01-01', 'private', 23 FROM DUAL UNION ALL
SELECT 'd', DATE '2011-01-01', 'other', 20 FROM DUAL;
Outputs:
NAME
DATE
WORK_TYPE
MINUTES
a
01-JAN-11
labor
53
a
01-JAN-11
other
19
a
01-JAN-11
private
58
b
01-JAN-11
labor
0
b
01-JAN-11
other
0
b
01-JAN-11
private
19
b
02-JAN-11
labor
31
b
02-JAN-11
other
24
b
02-JAN-11
private
0
c
01-JAN-11
labor
0
c
01-JAN-11
other
0
c
01-JAN-11
private
23
c
03-JAN-11
labor
25
c
03-JAN-11
other
0
c
03-JAN-11
private
50
d
01-JAN-11
labor
0
d
01-JAN-11
other
20
d
01-JAN-11
private
0
db<>fiddle here
In MySQL, you can use:
SELECT nd.name,
nd.date,
w.work_type,
COALESCE(t.minutes, 0) AS minutes
FROM (SELECT DISTINCT work_type FROM table1) w
CROSS JOIN
(SELECT DISTINCT name, date FROM table1) nd
LEFT OUTER JOIN table1 t
ON (t.name = nd.name AND t.date = nd.date AND t.work_type = w.work_type);
db<>fiddle here

split data in a single column into multiple columns in oracle

my_table :
Name
Value
item_1
AB
item_2
2
item_3
B1
item_1
CD
item_1
EF
item_2
3
item_3
B2
item_4
ZZ
required output:
item_1
item_2
item_3
item_4
AB
2
B1
ZZ
CD
3
B2
NULL
EF
NULL
NULL
NULL
SQL query :
with item_1 as (select value from my_table where name = 'item_1'),
item_2 as (select value from my_table where name = 'item_2'),
item_3 as (select value from my_table where name = 'item_3'),
item_4 as (select value from my_table where name = 'item_4')
select item_1.value, item_2.value,item_3.value, item_4.value from item_1 cross join item_2 cross join item_3 cross join item_4;
If I am using pivot along with MAX aggregate function, the query will display only max values of the corresponding items instead of displaying all the values.
Is there any way to split a single column into multiple columns(using where condition as mentioned in the above query) without cross join.
Use ROW_NUMBER and then PIVOT:
SELECT item_1,
item_2,
item_3,
item_4
FROM (
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY name ORDER BY ROWNUM) AS rn
FROM table_name t
)
PIVOT (
MAX(value) FOR name IN (
'item_1' AS item_1,
'item_2' AS item_2,
'item_3' AS item_3,
'item_4' AS item_4
)
)
Which, for the sample data:
CREATE TABLE table_name (Name, Value) AS
SELECT 'item_1', 'AB' FROM DUAL UNION ALL
SELECT 'item_2', '2' FROM DUAL UNION ALL
SELECT 'item_3', 'B1' FROM DUAL UNION ALL
SELECT 'item_1', 'CD' FROM DUAL UNION ALL
SELECT 'item_1', 'EF' FROM DUAL UNION ALL
SELECT 'item_2', '3' FROM DUAL UNION ALL
SELECT 'item_3', 'B2' FROM DUAL UNION ALL
SELECT 'item_4', 'ZZ' FROM DUAL;
Outputs:
ITEM_1
ITEM_2
ITEM_3
ITEM_4
AB
2
B1
ZZ
CD
3
B2
null
EF
null
null
null
db<>fiddle here
How about this?
DF column is calculated by row_number analytic function which partitions by each name (and sorts by value). It is ignored from the final column list, but its role is crucial in the GROUP BY clause.
SQL> with test (name, value) as
2 (select 'item_1', 'AB' from dual union all
3 select 'item_2', '2' from dual union all
4 select 'item_3', 'B1' from dual union all
5 select 'item_1', 'CD' from dual union all
6 select 'item_1', 'EF' from dual union all
7 select 'item_2', '3' from dual union all
8 select 'item_3', 'B2' from dual union all
9 select 'item_4', 'ZZ' from dual
10 ),
11 temp as
12 (select name, value,
13 row_number() over (partition by name order by value) df
14 from test
15 )
16 select
17 max(case when name = 'item_1' then value end) item_1,
18 max(case when name = 'item_2' then value end) item_2,
19 max(case when name = 'item_3' then value end) item_3,
20 max(case when name = 'item_4' then value end) item_4
21 from temp
22 group by df;
ITEM_1 ITEM_2 ITEM_3 ITEM_4
------ ------ ------ ------
AB 2 B1 ZZ
CD 3 B2
EF
SQL>

SQL | SPLIT COLUMNS INTO ROWS

How can I split the column data into rows with basic SQL.
COL1 COL2
1 A-B
2 C-D
3 AAA-BB
Result
COL1 Col2
1 A
1 B
2 C
2 D
3 AAA
3 BB
From Oracle 12, if it is always two delimited values then you can use:
SELECT t.col1,
l.col2
FROM table_name t
CROSS JOIN LATERAL (
SELECT SUBSTR(col2, 1, INSTR(col2, '-') - 1) AS col2 FROM DUAL
UNION ALL
SELECT SUBSTR(col2, INSTR(col2, '-') + 1) FROM DUAL
) l
Which, for the sample data:
CREATE TABLE table_name (COL1, COL2) AS
SELECT 1, 'A-B' FROM DUAL UNION ALL
SELECT 2, 'C-D' FROM DUAL UNION ALL
SELECT 3, 'AAA-BB' FROM DUAL;
Outputs:
COL1
COL2
1
A
1
B
2
C
2
D
3
AAA
3
BB
db<>fiddle here
Snowflake is tagged, so here's the snowflake way of doing this:
WITH TEST (col1, col2) as
(select 1, 'A-B' from dual union all
select 2, 'C-D' from dual union all
select 3, 'AAA-BB' from dual
)
SELECT test.col1, table1.value
FROM test, LATERAL strtok_split_to_table(test.col2, '-') as table1
ORDER BY test.col1, table1.value;
As of Oracle:
SQL> with test (col1, col2) as
2 (select 1, 'A-B' from dual union all
3 select 2, 'C-D' from dual union all
4 select 3, 'AAA-BB' from dual
5 )
6 select col1,
7 regexp_substr(col2, '[^-]+', 1, column_value) col2
8 from test cross join
9 table(cast(multiset(select level from dual
10 connect by level <= regexp_count(col2, '-') + 1
11 ) as sys.odcinumberlist))
12 order by col1, col2;
COL1 COL2
---------- ------------------------
1 A
1 B
2 C
2 D
3 AAA
3 BB
6 rows selected.
SQL>
For MS-SQL 2016 and higher you can use:
SELECT Col1, x.value
FROM t CROSS APPLY STRING_SPLIT(t.Col2, '-') as x;
BTW: If Col2 contains null, it does not appear in the result.

How can we get multiple rows data as single row in oracle

In image I have given table structure and sample data and I need output result as mentioned
With sample data you provided (lines #1 - 8), this returns desired result. Will it work for all other cases, I have no idea as the question lacks in quite a lot of information so YMMV.
SQL> with employee (id, name, type, visit_date) as
2 (select 1, 'Mohan', '01', date '2010-09-09' from dual union all
3 select 1, 'Mohan', '02', date '2010-09-10' from dual union all
4 --
5 select 1, 'Gani' , '01', date '2010-09-01' from dual union all
6 select 1, 'Gani' , '01', date '2010-09-02' from dual union all
7 select 1, 'Gani' , '01', date '2010-09-03' from dual
8 ),
9 --
10 type1 as
11 (select id, name, visit_date
12 from employee
13 where type = '01'
14 ),
15 type2 as
16 (select id, name, visit_date
17 from employee
18 where type = '02'
19 )
20 select
21 a.id,
22 a.name,
23 a.visit_date type1date,
24 b.visit_date type2date
25 from type1 a left join type2 b on a.id = b.id and a.name = b.name
26 order by a.id, a.name desc, a.visit_date;
ID NAME TYPE1DATE TYPE2DATE
---------- ----- ---------- ----------
1 Mohan 09/09/2010 10/09/2010
1 Gani 01/09/2010
1 Gani 02/09/2010
1 Gani 03/09/2010
SQL>

oracle -rearrange columns values based on value type

I have three oracle tables :
table_1:
ID some_fields
121 xx
122 xx
123 xx
124 xx
125 xx
create table table_1 as
select 121 id ,'xx' some_fields from dual
union select 122 id,'xx' some_fields from dual
union select 123 id,'xx' some_fields from dual
union select 124 id,'xx' some_fields from dual
union select 125 id,'xx' some_fields from dual
table_2:
ID some_fields
221 xx
222 xx
223 xx
224 xx
225 xx
create table table_2 as
select 221 id,'xx' some_fields from dual
union select 222 id,'xx 'some_fields from dual
union select 223 id,'xx' some_fields from dual
union select 224 id,'xx' some_fields from dual
union select 225 id,'xx' some_fields from dual
table3:
ID field_1 field_2
1 121 221
2 222 125
3 225 124
4 123 223
5 122 224
create table table_3 as
select 1 id, 121 field_1,221 field_2 from dual
union select 2 id, 222 field_1,125 field_2 from dual
union select 3 id, 225 field_1,124 field_2 from dual
union select 4 id, 123 field_1,223 field_2 from dual
union select 5 id, 122 field_1,224 field_2 from dual
I need to re-arrange table_3 to have all ids of table_1 in field_1 and all ids of table_2 in field_2 , knowing that ids in table_1 and table_2 are unique.
ID field_1 field_2
1 121 221
2 125 222
3 124 225
4 123 223
5 122 224
Noting in reality that these tables contain millions of rows.
I'm thinking of creating a view that accomplish my need but not sure how to proceed.
If I understand your question correctly, then according to your example, column FIELD_1 in TABLE_3 must contain only values from column ID in TABLE_1. Likewise, column FIELD_2 in TABLE_3 must contain only ID values from TABLE_2.
In your sample data, there are some values from TABLE_2 in column FIELD_1 and you want to update TABLE_3 so that only IDs from TABLE_1 appear in column FIELD_1 in TABLE_3.
If the above explanation is correct, then the following SQL will fix that:
update TABLE_3
set FIELD_1 = FIELD_2
,FIELD_2 = FIELD_1
where not exists (select 1 from TABLE_1 where TABLE_1.ID = TABLE_3.FIELD_1);
EDIT
(Due to your first comment.)
The following SQL query produces your desired result.
select T3.ID
,(select T1.ID from TABLE_1 T1 where T1.ID = T3.FIELD_1 or T1.ID = T3.FIELD_2) as FIELD_1
,(select T2.ID from TABLE_2 T2 where T2.ID = T3.FIELD_2 or T2.ID = T3.FIELD_1) as FIELD_2
from TABLE_3 T3
EDIT 2
(Due to your second comment.)
Using joins.
select T3.ID
,T1.ID as FLD_1
,T2.ID as FLD_2
from TABLE_3 T3
join TABLE_2 T2 on (T2.ID = T3.FIELD_1 or T2.ID = T3.FIELD_2)
join TABLE_1 T1 on (T1.ID = T3.FIELD_1 or T1.ID = T3.FIELD_2)

Resources