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
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>
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
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>
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)
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