sql join with nested where clause - sql

I've got a problem trying to join two tables, sample tables I have are as follows
Orders Table (Odr)
Order_No Item No Order_Type Req_Qty
100 A 2 45
101 B 1 32
102 F 2 23
103 A 4 23
104 C 3 14
105 B 5 43
Item Location Table (Loc)
Item_No Location Qty
A X 100
A Y 200
B X 150
B Y 50
C X 75
C Y 150
F X 250
F Y 60
What i want to see is, Location X's qty for each item of order types 1, 2 and 3 and for orders where Req_Qty is larger than 0
like below,
Order_No Item No Order_Type Req_Qty X_Qty
100 A 2 45 100
101 B 1 32 150
102 F 2 23 250
104 C 3 14 75
now ive written a query like below for this but i feel like its not giving me right results
select Odr.*, Loc.Qty
from Odr
inner JOIN Loc
ON Odr.ITEM_no = Loc.ITEM_no
where (SOPTYPE = '1' and Req_Qty >0
or SOPTYPE = '2' and Req_Qty >0
or SOPTYPE = '3' and Req_Qty >0) AND Loc.Location = 'X'
could someone pleas check this for me if this is the correct way to get the result i want
thanks

the query looks fine. but you could make it more readable:
select Odr.*, Loc.Qty
from Odr
inner JOIN Loc
ON Odr.ITEM_no = Loc.ITEM_no
where (SOPTYPE = '1' or SOPTYPE = '2' or SOPTYPE = '3')
and Req_Qty > 0
and Loc.Location = 'X'
or
select Odr.*, Loc.Qty
from Odr
inner JOIN Loc
ON Odr.ITEM_no = Loc.ITEM_no
where SOPTYPE IS IN('1', '2', '3')
and Req_Qty > 0
and Loc.Location = 'X'

Related

Sql update table with joined sums of other tables

I'm trying to reduce storage with packages included in sold products.
Products can have different amounts of same packages and invoice can have different amounts of products in separate lines. Action should be performed against certain invoiceID.
Simplified tables (summary is not column, just added to ease up calculation):
Inv_rows
InvID ProdID Qty *Summary*
999 100 2 *100 = 10*
999 101 2 *101 = 2*
999 102 2 *102 = 2*
999 103 2 *103 = 10*
999 100 8
999 103 8
Pack_to_prod
ProdID PackID Qty
100 A 2 *A = 20*
100 B 1 *B = 10*
101 A 1 *A = 2*
101 B 1 *B = 2*
102 A 3 *A = 6*
103 B 2 *B = 20*
Storage
ItemID Qty
A 100 *A = 28*
B 100 *B = 32*
**Desired Result**
Storage
ItemID Qty
A 72 *(100-28)*
B 68 *(100-32)*
What I have tried is:
UPDATE Storage
SET Storage.Qty = Storage.Qty -
(SELECT SUM (Inv_rows.Qty * Pack_to_prod.Qty) FROM Inv_rows
WHERE Inv_rows.ProdID IN (SELECT ProdID FROM Pack_to_prod
WHERE Pack_to_prod.PackID=Storage.ItemID) AND Inv_rows.InvId = 999
)
FROM Inv_rows, Storage, Pack_to_prod
WHERE Inv_rows.ProdID = Pack_to_prod.ProdID
AND Pack_to_prod.PackID = Storage.ItemID
AND Inv_rows.InvID = 999
But the problem is the 'IN' since it doesn't match the rows but I can't use '=' as 'where' results more than one line.
Then I tried to simplify it for myself (as I'm not a professional) with a select clause to understand what exactly needs to be done..
SELECT
Pack_to_prod.PackID AS PackageID,
Inv_rows.ProdID AS ProductID,
Inv_rows.Qty AS ProductQty,
Pack_to_prod.Qty AS PackageQtyPerProduct,
Inv_rows.Qty*Pack_to_prod.Qty AS PackageTotal,
Storage.Qty AS StorageQty,
Storage.Qty - (Inv_rows.Qty * Pack_to_prod.Qty) AS NewStorageQty
FROM Pack_to_prod,Inv_rows,Storage
WHERE Inv_rows.ProdID = Pack_to_prod.ProdID
AND Pack_to_prod.PackID = Storage.ItemID
AND Inv_rows.InvID = 999
GROUP BY Inv_rows.ProdID, Pack_to_prod.PackID, Pack_to_prod.Qty, Storage.Qty, Inv_rows.Qty
Which results as simple list showing the problem why they can't be just summed up:
PackageID ProductID ProductQty PackageQtyPerProduct PackageTotal StorageQty NewStorageQty
A 100 2 2 4 100 96
A 100 8 2 16 100 84
B 100 2 1 2 100 98
B 100 8 1 8 100 92
A 101 2 1 2 100 98
B 101 2 1 2 100 98
A 102 2 3 6 100 94
B 103 2 2 4 100 96
B 103 8 2 16 100 84
But can't figure out how to make it run 'line by line' so that each 'Pack_to_prod.Qty' would be handled separately.
Any help in right direction appreciated.
This seems like some aggregations and joins. To get the changes in values, then:
select pp.packid, sum(p.qty * pp.qty) as new_qty
from (select ir.prodid, sum(qty) as qty
from inv_rows ir
group by ir.prodid
) p join
Pack_to_prod pp
on pp.prodid = p.prodid
group by pp.packid;
You can then use this in an update:
update s
set s.qty = s.qty - pp.new_qty
from storage s join
(select pp.packid, sum(p.qty * pp.qty) as new_qty
from (select ir.prodid, sum(qty) as qty
from inv_rows ir
group by ir.prodid
) p join
Pack_to_prod pp
on pp.prodid = p.prodid
group by pp.packid
) pp
on pp.packid = s.itemid;
This was explained very well. The SQL code is user older coding conventions (such as JOIN conditions in the WHERE clause, instead of FROM) and isn't organized into subqueries properly. All the pieces are present though. I think something like this is what you're looking for.
with
inv_cte(ProdID, sum_qty) as (
select ProdID, sum(Qty)
from Inv_rows
group by ProdID),
pack_cte(PackID, prod_qty) as (
select pp.PackID, sum(pp.Qty*ic.sum_qty)
from Pack_to_prod pp
join inv_cte ic on pp.ProdID=ic.ProdID
group by pp.PackID)
select s.ItemID, s.Qty-p.prod_qty as ResultQty
from Storage s
join pack_cte p on s.ItemID=p.PackID;
Update statement
with
inv_cte(ProdID, sum_qty) as (
select ProdID, sum(Qty)
from Inv_rows
group by ProdID),
pack_cte(PackID, prod_qty) as (
select pp.PackID, sum(pp.Qty*ic.sum_qty)
from Pack_to_prod pp
join inv_cte ic on pp.ProdID=ic.ProdID
group by pp.PackID)
update s
set Qty=Qty-p.prod_qty
from Storage s
join pack_cte p on s.ItemID=p.PackID;

sql server inner join two tables and filter with two fields, getting extra records

I am having issue with getting an SELECT with INNER JOIN between two tables to get the correct output.
SELECT *
FROM PERSON_TABLE
WHERE MYSOMETHINGID = 123
The results are
ID PERSON_ID PERSON IS_SELECTED IS_BACKUP MYSOMETHINGID
2 -1 PERSON1 0 0 123
3 12 PERSON2 0 1 123
4 13 PERSON3 1 0 123
5 15 PERSON4 0 1 123
6 22 PERSON5 0 0 123
select *
from ASSIGNED_TABLE
where MYSOMETHINGID = 123
ID PERSON_ID PERSON MYSOMETHINGID
3 12 PERSON2 123
4 13 PERSON3 123
5 15 PERSON4 123
I want to inner join both company and select only the record with IS_SELECTED = 1 and if the record from PERSON_TABLE exists in ASSIGNED_TABLE
Here is my queries
select *
from ASSIGNED_TABLE AT inner join
PERSON_TABLE PT
on PT.IS_SELECTED = 1 AND AT.PERSON_ID = PT.PERSON_ID
where AT.MYSOMETHINGID = 123
ID PERSON_ID PERSON MYSOMETHINGID IS_SELECTED IS_BACKUP
3 12 PERSON2 123 1 0
4 13 PERSON3 123 1 0
5 15 PERSON4 123 1 0
I was expecting PERSON13 since it is the only record with IS_SELECTED = 1. I don't understand why I am getting 3 records instead of 1 and strangely the IS_SELECTED is 1 for all 3 records and 0 for all IS_BACKUP
Any help is greatly appreciated. Thanks.
I think you need to also join on mysomethingid:
select *
from ASSIGNED_TABLE AT inner join
PERSON_TABLE PT
on PT.IS_SELECTED = 1 AND
AT.PERSON_ID = PT.PERSON_ID AND
AT.MYSOMETHINGID = PT.MYSOMETHINGID
where AT.MYSOMETHINGID = 123;
Try this
select *
from ASSIGNED_TABLE AT
inner join PERSON_TABLE PT
on AT.PERSON_ID = PT.PERSON_ID
where PT.IS_SELECTED = 1 AND MYSOMETHINGID = 123
Another way is to select only rows where is_selected = 1
select *
from ASSIGNED_TABLE AT inner join
PERSON_TABLE PT ON
AT.PERSON_ID = PT.PERSON_ID
where AT.MYSOMETHINGID = 123 AND PT.IS_SELECTED = 1

Hiding a row where value = 0 but count its other column values in total calculations - sql2008

I have tables like that: (C1-C2 varchar(10), C3-Number int)
WaitingData
C1 C2 C3 Number
A B 1 10
A B 2 0
A B 3 4
X B 4 2
CompletedData
C1 C2 C3 Number
A B 1 5
A B 2 2
A B 3 0
X B 4 12
I am using the query below to represent the data:
Select wd.C1,wd.C2,wd.C3,wd.Number as NW,cdd.Number as NC
into #AllData
from (Select C1,C2,C3,sum(Number) from WaitingData group by C1,C2,C3) wd
outer apply (Select C1,C2,C3,sum(Number)
from CompletedData cd
where wd.C1=cd.C1 and wd.C2=cd.C2 and wd.C3=cd.C3
) cdd
Select * from #AllData
union
Select C1='Total',C2='Total',C3=-1, sum(NW),sum(NW)
from #AllData
This is giving me an output like:
C1 C2 C3 NW NC
A B 1 10 5
A B 2 0 2
A B 3 4 0
X B 4 2 12
Total Total -1 16 19
However, I want to hide the rows that has no NW but calculate its regarding values while calculating the Total row (see NC below). The output I want is like:
C1 C2 C3 NW NC
A B 1 10 5
A B 3 4 0
X B 4 2 12
Total Total -1 16 19
I could not find a way to provide an output like this. Any help would be so appreciated!
------------------------------EDIT---------------------------------------
------------------------------EDIT---------------------------------------
When I have data in the tables like below, the outer apply is not working like I want, it does not include the data A B 2.
WaitingData
C1 C2 C3 Number
A B 1 10
A B 3 4
X B 4 2
CompletedData
C1 C2 C3 Number
A B 1 5
A B 2 2
X B 4 12
And the output would be like:
C1 C2 C3 NW NC
A B 1 10 5
A B 3 4 NULL
X B 4 2 12
Total Total -1 16 17
In this situation, what can I do to count "2" NC value having by A B 2 on the final result and see NC as 19 instead 17, except inserting all the records that included by CompletedData but WaitingData? (need an efficient way)
Wrap the final result with one more select and exclude rows where NW = 0.
select * from
(
Select * from #AllData
union
Select C1='Total',C2='Total',C3=-1, sum(NW),sum(NC)
from #AllData
) t
where NW <> 0
Edit: Using a full join to get all values from both tables.
with t as
(select coalesce(w.c1,c.c1) as c1,coalesce(w.c2,c.c2) as c2,coalesce(w.c3,c.c3) as c3
, coalesce(w.number,0) as nw , coalesce(c.number,0) as nc
from waitingdata w
full join completeddata c on w.c1 = c.c1 and w.c2=c.c2 and w.c3=c.c3)
select * from
(select * from t
union all
Select C1='Total',C2='Total',C3=-1, sum(NW),sum(NC)
from t) x where nw <> 0
You can do all of this in one query, without temporary tables, intermediate results, subqueries, or UNION by using the ROLLUP operator:
SELECT
WD.C1,
WD.C2,
WD.C3,
SUM(WD.Number) AS NW,
SUM(CD.Number) AS NC
FROM
dbo.WaitingData WD
LEFT OUTER JOIN CompletedData CD ON
CD.C1 = WD.C1 AND
CD.C2 = WD.C2 AND
CD.C3 = WD.C3
GROUP BY
WD.C1,
WD.C2,
WD.C3
WITH ROLLUP
HAVING
GROUPING_ID(WD.C1, WD.C2, WD.C3) IN (0, 7) AND
SUM(WD.Number) <> 0

Show null and not num values

My query
with with_user_earns as (
-- get father information (start)
select father.id, father.str_name, father.id_father, father.ind_father_side_type, 1 as int_user_level from tb_user father where id = #v_user_id
union all
-- get son information (stop condition)
select son.id, son.str_name, son.id_father, son.ind_father_side_type, WUE.int_user_level + 1
from tb_user as son inner join with_user_earns as WUE on son.id_father = WUE.id
where son.id_father is not null and WUE.int_user_level < #v_max_level
)
select aux.*
from (
-- show result
select with_user_earns.id id_son, with_user_earns.str_name str_son_name, with_user_earns.id_father, father.str_name str_father_name, with_user_earns.ind_father_side_type, with_user_earns.int_user_level, isnull(sum(o.int_score), 0) as int_score
from with_user_earns inner join tb_order o on o.id_user = with_user_earns.id
inner join tb_user as father on father.id = with_user_earns.id_father
where o.dt_insert between #v_cycle_begin and #v_cycle_end and o.ind_payment_status = 3
group by with_user_earns.id, with_user_earns.str_name, with_user_earns.id_father, with_user_earns.ind_father_side_type, with_user_earns.int_user_level, father.str_name
) as aux
order by aux.int_user_level, aux.id_son
The table with_user_earns contains a lot of users (mult nivel hierarchy).
Then I want to join with tb_order to get int_score 0 if the user sell nothing and if the user sell anything I want the sum of it.
I tried put left join, full outer join, ... But no one works perfect
What a need to do?
My result:
id_son int_score
1 100
2 11100
3 100
10 300
Expected result:
id_son int_score
1 100
2 11100
3 100
4 0
5 0
6 0
7 0
8 0
9 0
10 300

Cross join on subquery

Fee Table
FeeId(PK)managerId amount Type
1 50 100 1
1 50 10000 39
1 50 50000 2
1 50 50000 3
1 50 50000 4
Manager Table
FeeId(FK)Split managerId
1 70 68
Desired Results:
FeeId managerId amount Type
1 50 30 1
1 68 70 1
1 50 3000 39
1 68 7000 39
1 50 15000 2
1 68 35000 2
1 50 15000 3
1 68 35000 3
1 50 15000 4
1 68 35000 4
This dataset is just one record, there are many more FeeId's in my data. A cross join would not take this into account. I basically want to cross join each manager based on the feeId.
The amount column is then recalculated to 70,30 for managerid 68,50 respectivly.
How do I do a cross join on each subset: WHERE f.feeId = m.feeId to get the desired results?
Example of cross join with incorrect results since the manager table will have more then 1 fee:
SELECT
f.feeId,
(cast(m.split as decimal) / 100) * f.amount as amount
FROM
dbo.fee f
CROSS JOIN dbo.manager m
As I understand this problem, you are trying to allocate the amount in fee between the two managers. The following query does this by cross joining an additional table, which is used to choose the data for each row.
select f.feeid,
(case when n.n = 1 then f.managerid
when n.n = 2 then m.managerid
end) as managerid,
(case when n.n = 1 then f.amount * (100 - m.split)/100
when n.n = 2 then f.amount * m.split/100
end) as amount, f.type
from fee f cross join
manager m cross join
(select 1 as n union all select 2) as n;
As a comment, this seems like a very unusual data structure.
It seems like this should work:
SELECT f.feeId, ,f.managerID, (cast(m.split as decimal) / 100) * f.amount as amount, f.type
FROM fee f
JOIN manager m
ON f.FeeID = m.FeeID
AND f.managerID = m.managerID