join table with itself to create more row - oracle

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

Related

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>

Oracle query to keep looking until value is not 0 anymore

I am using Oracle 11.
I have 2 tables
TblA with columns id, entity_id and effective_date.
TblADetail with columns id and value.
If Value = 0 for the effective date, I want to keep looking for the next effective date until I found value <> 0 anymore.
The below query only look for value on 3/10/21.
If value = 0, I want to look for value on 3/11/21. If that's not 0, I want to stop.
But, if that's 0, I want to look for value on 3/12/21. If that's not 0, I want to stop.
But, if that's 0, I want to keep looking until value is not 0.
How can I do that ?
SELECT SUM(pd.VALUE)
FROM TblA p,TblADetail pd
WHERE p.id = pd.id
AND p.effective_date = to_date('03/10/2021','MM/DD/YYYY')
AND TRIM (p.entity_id) = 123
Sample data:
TblA
id entity_id effective_date
1 123 3/10/21
2 123 3/11/21
3 123 3/12/21
TblADetail
id value
1 -136
1 136
2 2000
3 3000
In the above data, for entity_id 123, starting from effective_date 3/10/21, I would like to to return value 2000 (from TblADetail) effective_date 3/11/21.
So, starting from a certain date, I want the results from the minimum date that has non-zero values.
Thank you.
You can do what you need to do by grouping the sum on the effective date, and using the MIN analytic function to find the earliest date. Once you've done that, you simply need to select the date that matches the earliest date.
E.g.:
with tbla as (select 1 id, ' 123' entity_id, to_date('10/03/2021', 'dd/mm/yyyy') effective_date from dual union all
select 2 id, ' 123' entity_id, to_date('11/03/2021', 'dd/mm/yyyy') effective_date from dual union all
select 3 id, ' 123' entity_id, to_date('12/03/2021', 'dd/mm/yyyy') effective_date from dual),
tbla_detail as (select 1 id, -136 value from dual union all
select 1 id, 136 value from dual union all
select 2 id, 2000 value from dual union all
select 3 id, 3000 value from dual),
results as (select a.effective_date,
sum(ad.value) sum_value,
min(case when sum(ad.value) != 0 then a.effective_date end) over () min_effective_date
from tbla a
inner join tbla_detail ad on a.id = ad.id
where a.effective_date >= to_date('10/03/2021', 'dd/mm/yyyy')
and trim(a.entity_id) = '123'
group by a.effective_date)
select sum_value
from results
where effective_date = min_effective_date;
SUM_VALUE
----------
2000
Straightforward; read comments within code. Sample data in lines #1 - 13, query begins at line #14.
SQL> with
2 -- sample data
3 tbla (id, entity_id, effective_date) as
4 (select 1, 123, date '2021-03-10' from dual union all
5 select 2, 123, date '2021-03-11' from dual union all
6 select 3, 123, date '2021-03-12' from dual
7 ),
8 tblb (id, value) as
9 (select 1, -136 from dual union all
10 select 1, 136 from dual union all
11 select 2, 2000 from dual union all
12 select 3, 3000 from dual
13 ),
14 tblb_temp as
15 -- simple grouping per ID
16 (select id, sum(value) value
17 from tblb
18 group by id
19 )
20 -- return TBLA values whose ID equals TBLB_TEMP's minimum ID
21 -- whose value isn't zero
22 select a.id, a.entity_id, a.effective_date
23 from tbla a
24 where a.id = (select min(b.id)
25 from tblb_temp b
26 where b.value > 0
27 );
ID ENTITY_ID EFFECTIVE_
---------- ---------- ----------
2 123 03/11/2021
SQL>

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>

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- JOIN 2 tables with 2 ID's in common

table "team1" :
id country
1 India
2 Pakistan
3 srilanka
4 England
table "team2" :
id name name2
1 2 4
2 1 3
i have to combine two tables
another table when retrieve the data that time in place of 2 , 4 Pakistan,England
It is about the self join of team1 table (lines #15 and 16):
SQL> with
2 team1 (id, country) as
3 (select 1, 'India' from dual union all
4 select 2, 'Pakistan' from dual union all
5 select 3, 'Sri Lanka' from dual union all
6 select 4, 'England' from dual
7 ),
8 team2 (id, name, name2) as
9 (select 1, 2, 4 from dual union all
10 select 2, 1, 3 from dual
11 )
12 select b.id,
13 t1.country,
14 t2.country
15 from team2 b join team1 t1 on t1.id = b.name
16 join team1 t2 on t2.id = b.name2
17 order by b.id;
ID COUNTRY COUNTRY
---------- --------- ---------
1 Pakistan England
2 India Sri Lanka
SQL>
Just showing another way of writing the same query with aggregate functions and grouping.
with
team1 (id, country) as
(select 1, 'India' from dual union all
select 2, 'Pakistan' from dual union all
select 3, 'Sri Lanka' from dual union all
select 4, 'England' from dual
),
team2 (id, name, name2) as
(select 1, 2, 4 from dual union all
select 2, 1, 3 from dual
)
SELECT
T2.ID,
MAX(CASE
WHEN T2.NAME = T1.ID THEN T1.COUNTRY
END) AS TEAM1,
MAX(CASE
WHEN T2.NAME2 = T1.ID THEN T1.COUNTRY
END) AS TEAM2
FROM
TEAM2 T2
JOIN TEAM1 T1 ON T1.ID IN (
T2.NAME,
T2.NAME2
)
GROUP BY
T2.ID
ORDER BY
T2.ID;
Output:
ID TEAM1 TEAM2
---------- --------- ---------
1 Pakistan England
2 India Sri Lanka
Cheers!!

Resources