query regarding joining of two tables - sql

Suppose I have 2 below tables
sql> select * from fraud_types ;
fraud_id fraud_name
-------- ----------
1 Fraud 1
2 Fraud 2
3 Fraud 3
4 Fraud 4
5 Fraud 5
sql> select * from alarms ;
fraud_id dealer count
-------- ------ -----
1 Deal 1 5
3 Deal 1 3
5 Deal 1 4
1 Deal 2 2
2 Deal 2 6
3 Deal 2 1
4 Deal 2 7
5 Deal 2 9
I want to join the two tables and get the output as
dealer fraud_id count
------ -------- -----
Deal 1 1 5
Deal 1 2 0
Deal 1 3 3
Deal 1 4 0
Deal 1 5 4
Deal 2 1 2
Deal 2 2 6
Deal 2 3 1
Deal 2 4 7
Deal 2 5 9
Basically I want to include the fields from fraud_types also and just display 0 in the output if it is not present in the alarms table. How can I achieve this ? Please help
Regards

You can do this with a cross join to get all combinations and then a left outer join:
select d.dealer, f.fraud_id, coalesce(cnt, 0)
from (select distinct dealer from fraud_types) d cross join
fraud_types f left outer join
(select dealer, fraud_id, count(*) as cnt
from fraud_types
group by dealer, fraud_id
) df
on df.dealer = d.dealer and df.fraud_id = f.fraud_id
order by d.dealer, f.fraud_id;

Partitioned outer join is very useful for cases like this:
select a.dealer, f.fraud_id, nvl(a.count,0) count
from fraud_types f
left outer join alarms a
partition by (a.dealer)
on a.fraud_id = f.fraud_id
order by a.dealer, f.fraud_id
This does an outer join between alarms and fraud_types for every value of dealer found in alarms.
--
If the alarms table does not have (fraud,dealer) as key, then you can do a group by before the partition outer join:
select a.dealer, f.fraud_id, nvl(a.count,0) count
from fraud_types f
left outer join (
select fraud_id
, dealer
, sum(count) count
from alarms
group by fraud_id, dealer
) a
partition by (a.dealer)
on a.fraud_id = f.fraud_id
order by a.dealer, f.fraud_id

select distinct f.fraud_id,dealer,
(case when f.fraud_id=t.fraud_id then COUNT else 0 end) counts
from
fraud_types f
left join
alarms t
partition by (dealer)
on f.fraud_id=t.fraud_id
order by dealer

Related

SQL help i need to find the inventory remaining in my office

In sql help i have 3 tables, table one is asset table which is as follow
id
asset_code
asset_name
asset_group
asset_quantity
1
A001
demo asset
4
5
2
A002
demo asset 2
6
3
and another table is asset_allocation
id
asset_id
allocated_quantity
allocated_location
1
1
2
IT office
2
1
1
main hall
the last table is asset_liquidated which will present assets that are no longer going to be used
id
asset_id
liquidated_quantity
1
1
2
2
1
1
lets say i have 5 computers and i have allocated 3 computers and 1 is no longer going to be used so i should be remaining with 1 computer so now how do i make sql auto generate this math for me
You need to use aggregation and the join your tables -
SELECT id, asset_code, asset_name, asset_group, asset_quantity,
asset_quantity - COALESCE(AA.allocated_quantity, 0) - COALESCE(AL.liquidated_quantity, 0) available_quantity
FROM asset A
LEFT JOIN (SELECT asset_id, SUM(allocated_quantity) allocated_quantity
FROM asset_allocation
GROUP BY asset_id) AA ON A.id = AA.asset_id
LEFT JOIN (SELECT asset_id, SUM(liquidated_quantity) liquidated_quantity
FROM asset_liquidated
GROUP BY asset_id) AL ON A.id = AL.asset_id
This query will give you -1 as available_quantity for asset_id 1 as you have only 5 available, 3 of them are allotted and 3 are liquidated as per your sample data.
Please see if this helps
SELECT
asset_quantity AS Total_Assets
,ISNULL(allocated_quantity, 0) allocated_quantity
,ISNULL(liquidated_quantity, 0) liquidated_quantity
FROM asset
LEFT OUTER JOIN (
SELECT
asset_id, SUM(allocated_quantity) AS allocated_quantity
FROM asset_allocation
GROUP BY asset_id
) asset_allocation2
ON asset_allocation2.asset_id = asset.id
LEFT OUTER JOIN (
SELECT
asset_id, SUM(liquidated_quantity) AS liquidated_quantity
FROM asset_liquidated
GROUP BY asset_id
) asset_liquidated 2
ON asset_liquidated 2.asset_id = asset.id

Finding Minimum Values with Multiple Joins

I am using StandardSQL in BigQuery and have 7 tables with 10 to 75 columns each and thousands of rows. For simplicity I will only use the relevant tables and columns for what I am trying to accomplish.
Table 1
Item
Desc
12341
abcd
23451
bcda
34561
cdab
45671
dabc
Table 2
SubItem
Location
ON_OFF
OnHand
OnOrder
12345
1
ON
3
5
12345
2
ON
4
2
12345
3
ON
2
4
12346
1
ON
7
7
12346
2
ON
1
4
12346
3
ON
8
7
23451
1
OFF
1
1
23451
2
OFF
3
2
34567
1
ON
6
0
34567
2
ON
1
5
34568
1
ON
2
0
34568
2
ON
3
10
45671
2
ON
5
1
Table 3
Item
SubItem
12341
12346
23451
23451
34561
34567
34561
34568
Current Result
Item
Desc
ON_OFF
OH
OO
12341
abcd
ON
9
11
12341
abcd
ON
16
18
23451
bcda
OFF
4
3
34561
cdab
ON
7
5
34561
cdab
ON
5
10
45671
dabc
ON
5
1
Desired Result
Item
Desc
ON_OFF
OH
OO
12341
abcd
ON
9
18
23451
bcda
OFF
4
3
34561
cdab
ON
5
5
45671
dabc
ON
5
1
I am looking for the Minimum OH and Minimum OO Value for each item and as in the case of Item 45671, that does not correspond with the same SubItem number.
Current code providing me with the Current Result table is:
Select
Table1.Item,
Table1.Desc,
Table2.ON_OFF,
Table2.OH,
Table2.OO
From Table1
Left Join Table3
On Table1.Item = Table3.Item
Left Join
(Select SubItem, ON_OFF, Sum(OnHand) As OH, Sum(OnOrder) As OO
From Table 2
Group by 1,2)
ON Table3.SubItem = Table2.SubItem;
Looking for ideas as I am still fairly new to SQL and the current actual code ties 7 tables with various joins to build a final table with 45 columns and thousands of rows. I have looked at using RowNumber() and Partition By, but I am not sure where it would go. Was also thinking separating the OO and OH into two joins might help.
Any suggestions welcome! Thank you!
Looking at your sample data, It seems that You can use group by and aggregate function min as follows:
Select Table1.Item,
Table1.Desc,
Table2.ON_OFF,
Min(Table2.OH),
Min(Table2.OO)
From Table1
Left Join Table3
On Table1.Item = Table3.Item
Left Join (Select SubItem,
ON_OFF,
Sum(OnHand) As OH,
Sum(OnOrder) As OO
From Table2
Group by 1,2) Table2
ON Table3.SubItem = Table2.SubItem
Group by Table1.Item, Table1.Desc, Table2.ON_OFF;
I worked with it after getting some much needed sleep...
I came up with the below and it is working!
SELECT T1.Item,
T1.Desc,
T3_1.ONOFF,
T3_1.OH,
T3_2.OO
FROM Table1 T1
Left Join
(Select Item, SubItem,T2_1.O_O as ONOFF, T2_1.OH1 as OH,
ROW_NUMBER() OVER(PARTITION BY Item ORDER BY T2_1.OH1) as rn
FROM T2_1
Left Join
(Select SubItem, SUM(IFNULL(OnHand,0)) AS OH1,
FROM Table2
GROUP BY 1) T2_1
ON T2_1.SubItem = T3_1.SubItem) T3_1
On T1.Item = T3_1.Item
Left Join
(Select Item, SubItem, T2_2.OO1 as OO,
ROW_NUMBER() OVER(PARTITION BY Item ORDER BY T2_2.OO1) as rn2
FROM T2_2
Left Join
(Select SubItem, SUM(IFNULL(OnOrder,0)) AS OO1,
FROM Table2
GROUP BY 1) T2_2
ON T2_2.SubItem = T3_2.SubItem) T3_2
On T1.Item = T3_2.Item
Where rn = 1 and rn2 = 1;
Thanks!

SQL split one column into two columns based on values and use columns

Table: ProductionOrder
Id Ordernumber Lotsize
1 Order1 50
2 Order 2 75
3 WO-order1 1
4 WO-order2 1
Table: history
Id ProductionOrderID Completed
1 3 1
2 3 1
3 4 1
4 4 1
Table: ProductionOrderDetail
ID ProductionOrderID ProductionOrderDetailDefID Content
1 1 16 50
2 1 17 7-1-2018
3 2 16 75
4 2 17 7-6-2018
Start of my code:
Select p.ID, p.OrderNumber,
Case productionOrderDetailDefID
Where(Select pd1.productionOrderDetailDefID where ProductionOrderDetialDefID = 16) then min(pd1.content)
from ProductionOrder p
Left join History h1 on p.id = h1.productionOrderID
Left Join ProductionOrderDetail pd1 on p.ID = ProductionOrderID
The result in trying to get is
Id Ordernumber Lotsize Productionorder Completed
1 Order1 50 WO-order1 2
2 Order 2 75 WO-order2 2
Any help would be appreciated.
Try this
SELECT ordernumber,lotsize,Ordernumber,count(Ordernumberid)
FROM productionorder inner join history on productionorder.id = history.Ordernumberid
GROUP BY Ordernumber;
A bit of weird joins going on here. You should add this to a SQL fiddle so that we can see our work easier.
A link to SQL fiddle: http://sqlfiddle.com/
Here is my first attempt
SELECT
po.id
, po.ordernumber
, po.lotsize
, po2.productionorder
, SUM(h.completed)
FROM productionorder as po
INNER JOIN history as h
ON h.id = po.id
INNER JOIN prodcuctionorder as po2
ON po2.ordernumberid = h.ordernumberid
WHERE po.id NOT EXISTS IN ( SELECT ordernumberid FROM history )
GROUP BY
po.id
, po.ordernumber
, po.lotzise
, po2.productionorder
How far does that get you?

Group by with two columns

I am trying to write a query using group by in sub query ,I referred lot of blogs but could not get all the values.
I have three tables and below is the structure of those tables.
Pet_Seller_Master
ps_id ps_name city_id
2 abc 1
3 xyz 2
4 fer 4
5 bbb 1
City_Master
city_id city_name
1 Bangalore
2 COIMBATORE
4 MYSORE
Api_Entry
api_id ps_id otp
1 2 yes
2 3
3 2 yes
4 3 yes
5 4
6 5 yes
7 5 yes
8 5 yes
Query is to get number of sellers, no of pet sellers with zero otp, no of pet sellers with 1 otp, no of pet sellers with 2 otp,no of pet sellers with otp>2 for the particular city and within date range.
Through Below query I am able to get city , psp , and zero otp
select cm.city_name,
count(ps.ps_id) as PSP,
((select count(ps1.ps_id)
FROM ps_master ps1
WHERE ps1.city = cm.city_id)-
(SELECT count(distinct ps1.ps_id)
from ps_master ps1
INNER JOIN api_entry ae ON ps1.ps_id = ae.ps_id and otp!=''
WHERE ps1.city = cm.city_id and date(timestamp) >= curdate() - INTERVAL DAYOFWEEK(curdate())+6 DAY AND date(timestamp) < curdate())) as zero_psp
from ps_master ps INNER JOIN city_master cm ON ps.city = cm.city_id and cm.city_type = 'IN HOUSE PNS'
group by city_id
Please tell me the solution to solve this query.
Thanks in advance
It's not hard to do and you were on a right track. Here is what I would use:
select c.city_name, a.otp, p.ps_name, COUNT(*) nbr
from Api_Entry a
inner join Pet_Seller_Master p on p.ps_id=a.ps_id
inner join City_Master c on p.city_id=c.city_id
group by c.city_name, a.otp, p.ps_name
Now, if you want to get the number of sellers with zero otp, you just apply where clause:
where otp <> 'yes'
If you want to get the number of pet sellers with otp>2, then you just use subquery:
select *
from (
select c.city_name, a.otp, p.ps_name, COUNT(*) nbr
from #tempA a
inner join #tempP p on p.ps_id=a.ps_id
inner join #tempC c on p.city_id=c.city_id
group by c.city_name, a.otp, p.ps_name
) g
where nbr > 2

Oracle Outer join with 0 value return for non existing rows

I have 2 tables
Person
--------------------
id name dept_id
---------------------
1 x 1
2 y 1
3 z 2
Feedback
------------------------------------
person_id f_date positive negative
------------------------------------
1 2014-05-05 10 4
1 2014-05-15 5 3
2 2014-05-11 3 8
Now my query is
SELECT p.id,
nvl(sum(positive),0) AS pf,
nvl(sum(negative),0) AS nf
FROM person p
LEFT OUTER JOIN feedback f ON p.id = f.person_id
WHERE f_date BETWEEN to_date('2014-05-04', 'YYYY-MM-DD')
AND to_date('2014-05-16', 'YYYY-MM-DD')
GROUP BY p.id
ORDER BY p.id;
I expect to see
id pf nf
---------------
1 15 7
2 3 8
3 0 0
but I don't see the the data for 3. In fact the data i get is only if the rows exist in feedback table as if its an equi join.
Your WHERE clause is turning the outer join into an inner join. The solution is to move the condition to the ON clause:
SELECT p.id, nvl(sum(positive),0) as pf, nvl(sum(negative),0) as nf
FROM person p left outer JOIN
feedback f
on p.id = f.person_id and
f.f_date between to_date('2014-05-04', 'YYYY-MM-DD') AND to_date('2014-05-16', 'YYYY-MM-DD')
GROUP BY p.id
ORDER BY p.id;