I have two tables like below:
1.MAPPING -
ID Mapping ID
A01 P01
A03 P03
2.MAIN -
ID Metric1 Metric2
A01 (null) 4.22
A02 (null) (null)
A03 145 127
A04 (null) 20
P01 68 (null)
P03 (null) (null)
I have to run query for a particular ID. But I have to check two conditions :
If that ID exists in MAPPING table and if one of the Metrics is null
then I have to take Metric value of the Mapping ID.
Suppose for A01 , it exists in MAPPING and Metric1 is null so we have to take the value of Metric1 of P01 i.e. 68. But for Metric2 as it is not null so
we don't have to consider P01.
Now suppose for A02 , it is not in the table MAPPING . So we will
show as it is.
I am using Oracle. Can you please help me how to make an efficient query for this ?
This?
SQL> with
2 mapping (id, mapping_id) as
3 (select 'A01', 'P01' from dual union all
4 select 'A03', 'P03' from dual
5 ),
6 main (id, metric1, metric2) as
7 (select 'A01', null, 4.22 from dual union all
8 select 'A02', null, null from dual union all
9 select 'A03', 145, 127 from dual union all
10 select 'A04', null, 20 from dual union all
11 select 'P01', 68, null from dual union all
12 select 'P03', null, null from dual
13 )
14 select n.id,
15 case when n.metric1 is null then x.metric1 else n.metric1 end metric1,
16 case when n.metric2 is null then x.metric2 else n.metric2 end metric2
17 from main n left join mapping g on n.id = g.id
18 left join main x on x.id = g.mapping_id
19 order by n.id;
ID METRIC1 METRIC2
--- ---------- ----------
A01 68 4,22
A02
A03 145 127
A04 20
P01 68
P03
6 rows selected.
SQL>
Consider query that uses Main twice, joined to each field of Mapping:
SELECT Main.ID, IIf([Main].[Metric1] Is Null,[Main_1].[Metric1],Main.Metric1) AS M1,
IIf([Main].[Metric2] Is Null,[Main_1].[Metric2],Main.Metric2) AS M2
FROM Main AS Main_1
RIGHT JOIN (Main LEFT JOIN Mapping ON Main.ID = Mapping.ID)
ON Main_1.ID = Mapping.MappingID;
Related
beacause of a really old db design I need some help. This might be quite simple I'm just not seeing the wood for the trees at the moment.
TABLE A:
ID
1
2
3
4
5
TABLE B:
ID
VALUE B
1
10
1
20
2
10
2
20
3
10
3
20
3
30
4
10
TABLE C:
ID
VALUE C
1
11
1
21
2
11
2
21
2
31
3
11
5
11
Expected result:
where ID = 1
ID
VALUE B
VALUE C
1
10
11
1
20
21
where ID = 2
ID
VALUE B
VALUE C
2
10
11
2
20
21
2
null
31
where ID = 3
ID
VALUE B
VALUE C
3
10
11
3
20
null
3
30
null
where ID = 4
ID
VALUE B
VALUE C
4
10
null
where ID = 5
ID
VALUE B
VALUE C
5
null
11
The entries in table B and C are optional and could be unlimited, the ID from table A is the connection.
B and C are not directly connected. I need a quantitative comparision to find gaps in the database. The number of entries of table B and C should be the same (but not the value), usually entries are missing in either B or C.
I tried it with outer joins but I'm getting two much rows, because I need B or C join only one time per single row.
I hope anybody understand my problem and can help me.
It looks like, for each distinct ID, you want the nth row (ordered by VALUE) from TABLE_A to match with the nth row from TABLE_B. And if one table - A or B - has more values, you want those to match to null.
Your solution will have two parts. First, use row_number() over ( partition by id order by value) to order the rows in both tables. Then, use FULL OUTER JOIN to join on (id, rownumber).
Here is a full example:
-- WITH clauses are just test data...+
with table_a (id) as (
SELECT 1 FROM DUAL UNION ALL
SELECT 2 FROM DUAL UNION ALL
SELECT 3 FROM DUAL UNION ALL
SELECT 4 FROM DUAL UNION ALL
SELECT 5 FROM DUAL ),
table_b (id, value) as (
SELECT 1,10 FROM DUAL UNION ALL
SELECT 1,20 FROM DUAL UNION ALL
SELECT 2,10 FROM DUAL UNION ALL
SELECT 2,20 FROM DUAL UNION ALL
SELECT 3,10 FROM DUAL UNION ALL
SELECT 3,20 FROM DUAL UNION ALL
SELECT 3,30 FROM DUAL UNION ALL
SELECT 4,10 FROM DUAL ),
table_c (id, value) as (
SELECT 1,11 FROM DUAL UNION ALL
SELECT 1,21 FROM DUAL UNION ALL
SELECT 2,11 FROM DUAL UNION ALL
SELECT 2,21 FROM DUAL UNION ALL
SELECT 2,31 FROM DUAL UNION ALL
SELECT 3,11 FROM DUAL UNION ALL
SELECT 5,11 FROM DUAL )
-- Solution begins here
SELECT id, b.value b_value, c.value c_value
FROM ( SELECT b.*,
row_number() OVER ( PARTITION BY b.id ORDER BY b.value ) rn
FROM table_b b ) b
FULL OUTER JOIN ( SELECT c.*,
row_number() OVER ( PARTITION BY c.id ORDER BY c.value ) rn
FROM table_c c ) c USING (id, rn)
ORDER BY id, b_value, c_value;
+----+---------+---------+
| ID | B_VALUE | C_VALUE |
+----+---------+---------+
| 1 | 10 | 11 |
| 1 | 20 | 21 |
| 2 | 10 | 11 |
| 2 | 20 | 21 |
| 2 | | 31 |
| 3 | 10 | 11 |
| 3 | 20 | |
| 3 | 30 | |
| 4 | 10 | |
| 5 | | 11 |
+----+---------+---------+
I have two tables, one of them is a main table and the other is the decode. The decode has 142 rows and 2 columns. Cause of death code and description. The main table has person information and the reason of death and secondary reason of death.
Decode table
code
description
1
infection
2
covid
main table
client
reason_1
reason_2
01
1
null
02
2
1
03
1
2
Expected table
client
reason_1
reason_2
reason_1_desc
reason_2_desc
01
1
null
infection
null
02
2
1
covid
infection
03
1
2
infection
covid
How can I get this output without typing in all the values from decode table and using decode function or subquery factoring?
Join the description table twice (for each of two reasons):
Sample data:
SQL> with
2 t_decode (code, description) as
3 (select 1, 'infection' from dual union all
4 select 2, 'covid' from dual
5 ),
6 t_main (client, reason, reason_2) as
7 (select '01', 1, null from dual union all
8 select '02', 2, 1 from dual union all
9 select '03', 1, 2 from dual
10 )
Query:
11 select m.client, m.reason, m.reason_2,
12 d1.description reason_desc,
13 d2.description reason_2_desc
14 from t_main m left join t_decode d1 on d1.code = m.reason
15 left join t_decode d2 on d2.code = m.reason_2
16 order by m.client;
CL REASON REASON_2 REASON_DE REASON_2_
-- ---------- ---------- --------- ---------
01 1 infection
02 2 1 covid infection
03 1 2 infection covid
SQL>
I got a hard problem in sql that I can't resolve.
I show you it now:
table1
id id2 enter_date exit_date type
1 5 05/05/2021 11/05/2021 A
1 5 11/05/2021 20/05/2021 B
1 . 20/05/2021 30/05/2021 .
table2
id id2 enter_date exit_date type
1 5 08/05/2021 14/05/2021 A
1 5 14/05/2021 20/05/2021 B
1 5 20/05/2021 30/05/2021 C
My table 1 contains all good values but the problem is that she got missing value ( . ) and in my table2, I have every values. But all the values of table2 which are ever in the table 1 are false. But every value of table2 witch are not ever in table 1 are good.
So with my example, it gives me it :
table_final
id id2 enter_date exit_date type
1 5 05/05/2021 11/05/2021 A
1 5 11/05/2021 20/05/2021 B
1 5 20/05/2021 30/05/2021 C
SO I have good date, good type and no missing value.
I tried some thing with union all ... but nothing work.
Thanks for reading me !
This is how I understood the question. Read comments within code
SQL> with
2 -- sample data
3 table1 (id, id2, enter_date, exit_Date, type) as
4 (select 1, 5 , date '2021-05-05', date '2021-05-11', 'A' from dual union all
5 select 1, 5 , date '2021-05-11', date '2021-05-20', 'B' from dual union all
6 select 1, null, date '2021-05-20', date '2021-05-30', null from dual
7 ),
8 table2 (id, id2, enter_date, exit_Date, type) as
9 (select 1, 5 , date '2021-05-08', date '2021-05-14', 'A' from dual union all
10 select 1, 5 , date '2021-05-14', date '2021-05-20', 'B' from dual union all
11 select 1, 5 , date '2021-05-20', date '2021-05-30', 'C' from dual
12 )
13 -- query that returns result you need
14 -- Remove "invalid" rows from TABLE1 (the ones whose ID2 and TYPE aren't null
15 -- (or equal to dot, as you put it)
16 select *
17 from table1
18 where id2 is not null
19 and type is not null
20 union
21 -- From TABLE2, take rows that don't exist in TABLE1 already (matched by ID, ID2 and TYPE)
22 -- where ID2 and TYPE aren't NULL (in TABLE1).
23 select *
24 from table2
25 where (id, id2, type) not in (select id, id2, type
26 from table1
27 where id2 is not null
28 and type is not null
29 );
ID ID2 ENTER_DATE EXIT_DATE T
---------- ---------- ---------- ---------- -
1 5 05/05/2021 11/05/2021 A
1 5 11/05/2021 20/05/2021 B
1 5 20/05/2021 30/05/2021 C
SQL>
i am currently working in a database that has a table that looks like this:
ID | Type | Value
11111 | Type1 | 45
11111 | Type2 | 85
11111 | Type3 | 26
11111 | Type4 | 69
11112 | Type1 | 14
11112 | Type2 | 36
11113 | Type1 | 69
11113 | Type3 | 25
This table works as followed:
Each ID appears multiple times in the table.
Each ID has one or more types.
Each type has a value
In the example above you can see that the ID 11112 does not have a Type3 or a Type4 and that ID 11113 does not have a Type2 or Type4.
The problem with this is that some of these types (with the corresponding value) should be there for every ID, to make this happen a list should be created with all the ID's that are missing one or more of these types. This is so that it's easy to see what id's need their type and value added.
Is there a query that can make such a list? One that gives the Unique ID's of every instance that is missing one or more types? I was able to get the ID with only a specific type missing, but i have not been able to make it so that the ID is listed of any type is missing.
You can generate all required types and id combinations and then filter out the ones that exist:
with required_types as (
select 'type3' as type from dual union all
select 'type4' as type from dual
)
select i.id, rt.type
from (select distinct id from t) i cross join
required_types rt left join
t
on t.id = i.id and t.type = rt.type
where t.id is null;
If all types present in the data are required, you can use (select distinct type from t).
This query shows all ID's where at least one type is missing:
SELECT ID
FROM T
GROUP BY ID
HAVING COUNT(DISTINCT TYPE)<(SELECT COUNT(DISTINCT TYPE) FROM T)
Not very elegant, but will return IDs and types they are missing. I removed superfluous "1111" from IDs and "ype" from types (was too lazy to type them all).
SQL> with test (id, type) as
2 (select 1, 't1' from dual union all
3 select 1, 't2' from dual union all
4 select 1, 't3' from dual union all
5 select 1, 't4' from dual union all
6 --
7 select 2, 't1' from dual union all
8 select 2, 't2' from dual union all
9 --
10 select 3, 't1' from dual union all
11 select 3, 't3' from dual
12 ),
13 all_types as
14 (select distinct type from test)
15 --
16 select t.id, a.type
17 from test t join all_types a on 1 = 1
18 minus
19 select t.id, t.type
20 from test t;
ID TY
---------- --
2 t3
2 t4
3 t2
3 t4
SQL>
There are three tables in my db: ITEM_MASTER, PRICE_MASTER and COMP_MASTER.
ITEM_MASTER
STORE_CODE ITEM_CODE ITEM_DESC
011 914004 desccc
PRICE_MASTER
STORE_CODE ITEM_CODE COMP_CODE
011 914004 01
011 914004 02
011 914004 03
011 914004 04
COMP_MASTER
COMP_CODE COMP_DESC STORE_CODE
01 comp1 011
02 comp2 011
03 comp3 011
04 comp4 011
I want to get all these for an ITEM_CODE in a single query.
STORE_CODE ITEM_CODE ITEM_DESC COMP_DESC1 COMP_DESC2 COMP_DESC3 COMP_DESC4
011 914004 desccc comp1 comp2 comp3 comp4
How can I write an oracle SQL query for this?
There are two steps involved to get this output: a join and a pivot.
An example:
First create your sample tables:
SQL> create table item_master (store_code,item_code,item_desc)
2 as
3 select '011', 914004, 'desccc' from dual
4 /
Table created.
SQL> create table price_master (store_code,item_code,comp_code)
2 as
3 select '011', 914004, '01' from dual union all
4 select '011', 914004, '02' from dual union all
5 select '011', 914004, '03' from dual union all
6 select '011', 914004, '04' from dual
7 /
Table created.
SQL> create table comp_master (comp_code,comp_desc,store_code)
2 as
3 select '01', 'comp1', '011' from dual union all
4 select '02', 'comp2', '011' from dual union all
5 select '03', 'comp3', '011' from dual union all
6 select '04', 'comp4', '011' from dual
7 /
Table created.
First step is the join. Here I use ANSI join syntax, but you can use good old Oracle join syntax as well.
SQL> select i.store_code
2 , i.item_code
3 , i.item_desc
4 , c.comp_desc
5 from item_master i
6 inner join price_master p
7 on ( i.store_code = p.store_code
8 and i.item_code = p.item_code
9 )
10 inner join comp_master c
11 on ( p.store_code = c.store_code
12 and p.comp_code = c.comp_code
13 )
14 /
STO ITEM_CODE ITEM_D COMP_
--- ---------- ------ -----
011 914004 desccc comp1
011 914004 desccc comp2
011 914004 desccc comp3
011 914004 desccc comp4
4 rows selected.
The comp description appear below each other, but you want them to be next to each other. To achieve that, you pivot the result set. Note that you have to hard code the number of rows you want to pivot:
SQL> with t as
2 ( select i.store_code
3 , i.item_code
4 , i.item_desc
5 , c.comp_desc
6 , row_number() over (partition by i.store_code,i.item_code order by c.comp_code) rn
7 from item_master i
8 inner join price_master p
9 on ( i.store_code = p.store_code
10 and i.item_code = p.item_code
11 )
12 inner join comp_master c
13 on ( p.store_code = c.store_code
14 and p.comp_code = c.comp_code
15 )
16 )
17 select store_code
18 , item_code
19 , item_desc
20 , max(decode(rn,1,comp_desc)) comp_desc1
21 , max(decode(rn,2,comp_desc)) comp_desc2
22 , max(decode(rn,3,comp_desc)) comp_desc3
23 , max(decode(rn,4,comp_desc)) comp_desc4
24 from t
25 group by store_code
26 , item_code
27 , item_desc
28 /
STO ITEM_CODE ITEM_D COMP_ COMP_ COMP_ COMP_
--- ---------- ------ ----- ----- ----- -----
011 914004 desccc comp1 comp2 comp3 comp4
1 row selected.
Hope this helps.
Regards,
Rob.