Left Join in Oracle to Join columns with Null Value - oracle

I have a table like below :
Table_a :
Pos_id col1 col2 value
12221 null null Car
12222 112 1111 Bike
12222 112 1112 Bus
12222 112 1113 Roller
Table_b :
pos_id col1 col2 line_nr
12221 100 1000 1
12222 112 1111 1
12222 112 1112 2
12222 112 1113 3
I want to select the values of table_a whose line_nr is 1 in the table_b.
so I have tried LEFT JOIN.
select * from table_a
left join table_b
on a.pos_id = b.pos_id
and a.col1 = b.col1
and a.col2 = b.col2
where b.line_nr = 1;
So this doesnt select the column that has null in the table_a.
I need to select the below given columns from table_a
Pos_id col1 col2 value
12221 null null Car
12222 112 1111 Bike

You must use left outer join and the accept row with line_nr = 1 or NULL
SELECT a.POS_ID, a.COL1, a.COL2, a.VAL
FROM table_a a
LEFT OUTER JOIN table_b b
ON a.pos_id = b.pos_id
AND a.col1 = b.col1
AND a.col2 = b.col2
where nvl(b.line_nr,1) = 1
;
POS_ID COL1 COL2 VAL
---------- ---------- ---------- ------
12222 112 1111 Bike
12221 Car
This is probably what you mean - get rows from a that either match the b and have line_nr = 1 or do not match (i.e. line_nr is null)

Related

Converting rows into Column in Oracle without any relation

I have a query which will fetch two rows only and I want to bring second row data into columns with different column name.
Below is the original query result.
The expected result is like
Expected result.
Please help how shd I proceed, not able to figure out with PIVOT.
Here's one option; see comments within code.
SQL> with
2 your_query (column1, column2, column3) as
3 -- this is what your current query returns
4 (select 1, 'ABC', 123 from dual union all
5 select 2, 'XYZ', 456 from dual
6 ),
7 temp as
8 -- distinguish 1st from 2nd row
9 (select y.*,
10 row_number() over (order by column1) rn
11 from your_query y
12 )
13 -- finally, cross join two rows and conditionally display columns.
14 -- MAX is here to avoid empty "cells"
15 select max(case when a.rn = 1 then a.column1 end) as col1,
16 max(case when a.rn = 1 then a.column2 end) as col2,
17 max(case when a.rn = 1 then a.column3 end) as col3,
18 --
19 max(case when b.rn = 2 then b.column1 end) as col4,
20 max(case when b.rn = 2 then b.column2 end) as col5,
21 max(case when b.rn = 2 then b.column3 end) as col6
22 from temp a cross join temp b;
COL1 COL COL3 COL4 COL COL6
---------- --- ---------- ---------- --- ----------
1 ABC 123 2 XYZ 456
SQL>

Select columns as shown in resultant table - Oracle (Not working as expected)

I have a table name TABLE1 having 4 columns (ID, LINE, COST, CODE)
CREATE TABLE TABLE1 ( ID NUMBER(4), LINE NUMBER(3), COST NUMBER(4), CODE VARCHAR2(3) );
/*1st case:*/
INSERT INTO TABLE1 VALUES(101, 1, 40, 'ABC' );
INSERT INTO TABLE1 VALUES(101, 1, 50, 'DEF' );
/*2nd case:*/
INSERT INTO TABLE1 VALUES(102, 2, 30, 'CDE' );
INSERT INTO TABLE1 VALUES(102, 2, 20, 'ECD' );
/*3rd case:*/
INSERT INTO TABLE1 VALUES(103, 3, 5, 'BCD' );
INSERT INTO TABLE1 VALUES(103, 3, 5, 'BCD' );
/*4th case:*/
INSERT INTO TABLE1 VALUES(104, 4, 15, 'OPQ' );
INSERT INTO TABLE1 VALUES(104, 4, 15, 'PQO' );
ID LINE COST CODE
--------------------------
101 1 40 ABC
101 1 50 DEF
102 2 30 CDE
102 2 20 ECD
103 3 05 BCD
103 3 05 BCD
104 4 15 OPQ
104 4 15 PQO
From the above table you can see that I have taken a sum of cost of each ID with respective to each LINE...
For ID = 101 and LINE = 1 -> SUM(COST) = 40+50 = 90
For ID = 102 and LINE = 2 -> SUM(COST) = 30+20 = 50
For ID = 103 and LINE = 3 -> SUM(COST) = 05+05 = 10
For ID = 104 and LINE = 4 -> SUM(COST) = 15+15 = 30
I have a TABLE2 having 6 columns (ID,LINE, COST_PR, PR_CODE, COST_SC,SC_CODE)
CREATE TABLE TABLE2 ( ID NUMBER(4), LINE NUMBER(3), COST_PR NUMBER(4), PR_CODE VARCHAR2(3), COST_SC NUMBER(4), SC_CODE VARCHAR2(3) );
INSERT INTO TABLE2 VALUES(101, 1, 90, 'DFE', 100, 'CBA');
INSERT INTO TABLE2 VALUES(102, 2, 60, 'CDE', 50, 'EDC');
INSERT INTO TABLE2 VALUES(103, 3, 10, 'BCD', 10, 'DEF');
INSERT INTO TABLE2 VALUES(104, 4, 10, 'XYZ', 20, 'ZXY');
ID LINE COST_PR PR_CODE COST_SC SC_CODE
--------------------------------------------------------
101 1 90 DFE 100 CBA
102 2 60 CDE 50 EDC
103 3 10 BCD 10 DEF
104 4 10 XYZ 20 ZXY
I have a TABLE3 with 2 columns (SEC, PIN)
CREATE TABLE TABLE3( SEC VARCHAR2(3), PIN VARCHAR2(2) );
INSERT INTO TABLE3 VALUES ('ABC', 'A1' );
INSERT INTO TABLE3 VALUES ('DEF', 'A2' );
INSERT INTO TABLE3 VALUES ('CDE', 'A3' );
INSERT INTO TABLE3 VALUES ('ECD', 'A4' );
INSERT INTO TABLE3 VALUES ('BCD', 'A5' );
INSERT INTO TABLE3 VALUES ('OPQ', 'A7' );
INSERT INTO TABLE3 VALUES ('PQO', 'A8' );
INSERT INTO TABLE3 VALUES ('XYZ', 'B1' );
INSERT INTO TABLE3 VALUES ('ZXY', 'B2' );
INSERT INTO TABLE3 VALUES ('CBA', 'B3' );
INSERT INTO TABLE3 VALUES ('EDC', 'B4' );
INSERT INTO TABLE3 VALUES ('DFE', 'B5' );
SEC PIN
-------------
ABC A1
DEF A2
CDE A3
ECD A4
BCD A5
OPQ A7
PQO A8
XYZ B1
ZXY B2
CBA B3
EDC B4
DFE B5
The above resultant logic is
Case1:
From TABLE1, For ID = 101 & LINE = 1, SUM(COST) = 40+50 = 90
we need to compare this SUM(COST) with COST_PR and COST_SC of TABLE2,
In this case, SUM(COST) = COST_PR
so we need to
a) populate CODE values from TABLE1 and PR_CODE from TABLE2 in PR_CODE columns and
b) populate SC_CODE values from TABLE2 as it is in SC_CODE column
Case2:
From TABLE1, For ID = 102 & LINE = 2, SUM(COST) = 30+20 = 50
we need to compare this SUM(COST) with COST_PR and COST_SC of TABLE2,
In this case, SUM(COST) = COST_SC
so we need to
a) populate CODE values from TABLE1 and SC_CODE values from TABLE2 in SC_CODE columns and
b) populate PR_CODE values from TABLE2 as it is in PR_CODE columns
Case3:
From TABLE1, For ID = 103 & LINE = 3, SUM(COST) = 10
we need to compare this SUM(COST) with COST_PR and COST_SC of TABLE2,
In this case, SUM(COST) = COST_PR = COST_SC
so we need to
a) populate CODE values from TABLE1 and PR_CODE values from TABLE2 in PR_CODE columns and
b) populate CODE values from TABLE1 and SC_CODE values from TABLE2 in SC_CODE columns
Case4:
From TABLE1, For ID = 104 & LINE = 4, SUM(COST) = 30
we need to compare this SUM(COST) with COST_PR and COST_SC of TABLE2,
In this case, SUM(COST) <> COST_PR and SUM(COST)<> COST_SC
so we need to
a) populate PR_CODE values from TABLE2 in PR_CODE columns and
b) populate SC_CODE values from TABLE2 in SC_CODE columns of resultant table
Once this logic over, we will be using INNER JOIN with TABLE3 two times(once to populate PR_PIN values from TABLE3 in resultant table and second time to populate SC_PIN values from TABLE3 in resultant table)
The resultant table be like
ID LINE PR_CODE PR_PIN SC_CODE SC_PIN
---------------------------------------------------
/*1st case*/
101 1 ABC A1 CBA B3
101 1 DEF A2 CBA B3
101 1 DFE A2 CBA B3
/*2nd case*/
102 2 CDE A3 CDE A3
102 2 CDE A3 ECD A4
102 2 CDE A3 EDC B4
/*3rd case*/
103 3 BCD A5 BCD A5
103 3 BCD A5 DEF A2
/*4th case*/
104 4 XYZ B1 ZXY B2
This is the query I have used and its not working as expected...Can someone help me in this:
WITH tmp1 AS
(
SELECT DISTINCT t.*,
SUM(cost) OVER (PARTITION BY id, line) AS sum_code
FROM table1 t
)
SELECT t1.id, t1.line,
CASE
WHEN t2.cost_pr = t1.sum_code THEN t1.code
ELSE t2.pr_code
END AS pr_code,
CASE
WHEN t2.cost_pr = t1.sum_code THEN t31.pin
ELSE t32.pin
END AS pr_pin,
CASE
WHEN t2.cost_sc = t1.sum_code THEN t1.code
ELSE t2.sc_code
END AS sc_code,
CASE
WHEN t2.cost_sc = t1.sum_code THEN t31.pin
ELSE t33.pin
END AS sc_pin
FROM tmp1 t1
INNER JOIN table2 t2
ON t1.id = t2.id AND t1.line = t2.line
INNER JOIN table3 t31
ON t1.code = t31.sec
INNER JOIN table3 t32
ON t2.pr_code = t32.sec
INNER JOIN table3 t33
ON t2.sc_code = t33.sec;
No duplicates allowed in resultant table. Let me know if there is a typo mistake....With my query, I see 4th case is working as expected but remaining three cases are partially correct but not entirely correct...Can some one help me in this

Join Multiple tables based on value in one table

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>

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)

Update the top row of each group - Oracle

The need is to update only the top row of each group of a table from the data of other table.
I need to update table A with details from table B
Table A
---------
ID Name Date PCNO
1 abc 1/1/12 123
2 def 1/1/12 234
3 fgh 1/2/12 222
4 asd 1/2/12 234
TABLE B
-----------
ID Name Date PCNO
1 adsf 1/1/12 4343
2 sdf 1/2/12 9347
For each top record of table A grouped by "Date" and ordered by PCNO desc, I would like to update the values from table B.
Do i use rank for this purpose.?
You can use rank or dense-rank (or even row-number) to get identify the 'top' row, though you may need t consider what to do if ties are possible in your real data:
select a.id, a.name, a.date_col, a.pcno,
dense_rank() over (partition by date_col order by pcno desc) as rnk
from table_a a;
ID NAME DATE_COL PCNO RNK
---------- ---- ---------- ---------- ----------
2 def 2012-01-01 234 1
1 abc 2012-01-01 123 2
4 asd 2012-01-02 234 1
3 fgh 2012-01-02 222 2
And you can join to table B to get the new values for the top-ranked:
select a.id, a.name, a.date_col, a.pcno,
dense_rank() over (partition by a.date_col order by a.pcno desc) as rnk,
case when dense_rank() over (partition by a.date_col order by a.pcno desc) = 1
then b.name else a.name end as new_name,
case when dense_rank() over (partition by a.date_col order by a.pcno desc) = 1
then b.pcno else a.pcno end as new_pcno
from table_a a
join table_b b on b.date_col = a.date_col;
ID NAME DATE_COL PCNO RNK NEW_ NEW_PCNO
---------- ---- ---------- ---------- ---------- ---- ----------
2 def 2012-01-01 234 1 adsf 4343
1 abc 2012-01-01 123 2 abc 123
4 asd 2012-01-02 234 1 sdf 9347
3 fgh 2012-01-02 222 2 fgh 222
and you can then use that in a merge statement:
merge into table_a target
using (
select a.id, a.name, a.date_col, a.pcno,
dense_rank() over (partition by a.date_col order by a.pcno desc) as rnk,
case when dense_rank() over (partition by a.date_col order by a.pcno desc) = 1
then b.name else a.name end as new_name,
case when dense_rank() over (partition by a.date_col order by a.pcno desc) = 1
then b.pcno else a.pcno end as new_pcno
from table_a a
join table_b b on b.date_col = a.date_col
) source
on (source.id = target.id)
when matched then update
set target.name = source.new_name, target.pcno = source.new_pcno
where source.rnk = 1;
or maybe
merge into table_a target
using (
select a.id, a.name, a.date_col, a.pcno,
case when dense_rank() over (partition by a.date_col order by a.pcno desc) = 1
then b.name else a.name end as new_name,
case when dense_rank() over (partition by a.date_col order by a.pcno desc) = 1
then b.pcno else a.pcno end as new_pcno
from table_a a
join table_b b on b.date_col = a.date_col
) source
on (source.id = target.id)
when matched then update
set target.name = source.new_name, target.pcno = source.new_pcno
where target.name != source.new_name or target.pcno != source.new_pcno;
either of which reports 2 rows merged, and then:
select * from table_a;
ID NAME DATE_COL PCNO
---------- ---- ---------- ----------
1 abc 2012-01-01 123
2 adsf 2012-01-01 4343
3 fgh 2012-01-02 222
4 sdf 2012-01-02 9347
You may need to adjust it if there isn't always going to be a match for a date, though the inner join ought to take care of that.
db<>fiddle demo

Resources