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;
Related
I have a query from my products and factors and factor items for show them.
In this query I'm showing a report from factor for user.
My query is :
WITH CTE AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY FactoriTems.datesave ASC) AS rn,
FactoriTems.code, FactoriTems.replacement,
FactoriTems.suggcode, Factors.dateexport,
Productions.descriptions,
FactoriTems.countt, FactoriTems.price,
FactoriTems.countt * FactoriTems.price AS 'total',
Productions.country
FROM
Productions
INNER JOIN
FactoriTems ON Productions.code = FactoriTems.code
INNER JOIN
Factors ON Factors.gid = FactoriTems.gid
WHERE
(FactoriTems.gid = #gid)
)
SELECT *
FROM CTE
ORDER BY rn
This query is OK, but there is a problem, in Productions table some category have two or three product with one code, and when this codes are in factoritems table show two rows in my result set!
Result is :
rn
code
dateexport
descriptions
countt
price
total
1
aaa
12/24/2021
...
100
2
200
2
bbb
12/24/2021
...
200
3
600
3
ccc
12/24/2021
...
100
2
200
4
ddd
12/24/2021
...
200
3
600
5
ddd
12/24/2021
...
100
2
200
6
eee
12/24/2021
...
200
3
600
Now how can I show only one row for 'ddd' product code?
I tried to use DISTINCT but I got an error.
I want the output to be as follows:
rn
code
dateexport
descriptions
countt
price
total
1
aaa
12/24/2021
...
100
2
200
2
bbb
12/24/2021
...
200
3
600
3
ccc
12/24/2021
...
100
2
200
4
ddd
12/24/2021
...
200
3
600
5
eee
12/24/2021
...
200
3
600
Thanks
Just missing PARTITIN BY clause for the code column within the inner query. Rewrite your current query such as
WITH CTE AS
(SELECT ROW_NUMBER() OVER (PARTITION BY ft.code ORDER BY ft.datesave) AS rn0,
ft.code,
ft.replacement,
ft.suggcode,
f.dateexport,
p.descriptions,
ft.countt,
ft.price,
ft.countt * ft.price AS total,
p.country
FROM Productions p
JOIN FactoriTems ft
ON p.code = ft.code
JOIN Factors f
ON f.gid = ft.gid
WHERE (ft.gid = #gid))
SELECT ROW_NUMBER() OVER (ORDER BY datesave,code) AS rn,
code, replacement, suggcode, dateexport, descriptions,
countt, price, total, country
FROM CTE
WHERE rn0 = 1
ORDER BY rn
in order to filter out the duplicates for each distinct grouped code
Try this code:
WITH CTE AS
(SELECT ROW_Number() over (PARTITION BY FactoriTems.code ORDER by FactoriTems.datesave ASC) as rn,FactoriTems.code,
FactoriTems.replacement, FactoriTems.suggcode,Factors.dateexport,
Productions.descriptions, FactoriTems.countt, FactoriTems.price,
FactoriTems.countt * FactoriTems.price AS 'total', Productions.country
FROM Productions
INNER JOIN FactoriTems ON Productions.code = FactoriTems.code
INNER JOIN Factors ON Factors.gid = FactoriTems.gid
WHERE (FactoriTems.gid = #gid))
SELECT * FROM CTE
WHERE CTE.rn = 1
ORDER BY rn
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'
I have following data
Components
componentid title
1 houseRent
2 medical
3 Travelling Allowance
empPayrollMaster
MasterID EmployeeID SalaryMonthID
1 101 1
2 102 1
3 103 1
empPayrollDetail
DetailID MasterID ComponentID amount
1 1 1 100
2 1 2 500
3 2 1 300
4 2 3 250
5 3 1 150
6 3 2 350
7 3 3 450
Required Output
EmployeeID MasterID ComponentID amount
101 1 1 100
101 1 2 500
101 1 3 0
102 2 1 300
102 1 2 0
102 2 3 250
103 3 1 150
103 3 2 350
103 3 3 450
To get the required output if i do left outer join between components and empPayrollDetail I get null in EmployeeID and MasterID and amount Columns. How to modify left join to get the required output
You need to do a CROSS JOIN on Components and empPayrollMaster to generate first all combination of employees and components. Then, do a LEFT JOIN on empPayrollDetail to achieve the result, using ISNULL(amount, 0) for NULL amounts.
SQL Fiddle
SELECT
epm.EmployeeID,
epm.MasterID,
c.ComponentID,
amount = ISNULL(epd.amount, 0)
FROM empPayrollMaster epm
CROSS JOIN Components c
LEFT JOIN empPayrollDetail epd
ON epd.MasterID = epm.MasterID
AND epd.ComponentID = c.ComponentID
Try this
select empPayrollMaster.EmployeeID,empPayrollMaster.MasterID,
Components.componentid,isnull(empPayrollDetail.amount,0)
from empPayrollMaster
left join Components
on empPayrollMaster.EmployeeID is not null
left join empPayrollDetail
on empPayrollDetail.MasterID = empPayrollMaster.MasterID
and empPayrollDetail.ComponentID = Components.componentid
Try this way
select c.EmployeeID,d.MasterID,c.ComponentID,isnull(d.amount,0) as amount from (
select * from Components a
Cross join empPayrollMaster b) c
left outer join empPayrollDetail d on d.componentid =c.componentid
As you want the component amount for each employee in the master table you should use a insull(payrole_detail.amount,0) or, as #Turophile pointed out, the SQL standard function coalesce(payrole_detail.amount,0) for the amounts column.
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
INNER JOIN Orders
ON Customers.CustomerID=Orders.CustomerID
ORDER BY Customers.CustomerName;
I have 2 tables
Products table:
ID ProductName Category
0 T-Shirt 15
1 Aqua De Gio 12
2 Jacket 15
3 Hot Water 13
Categories table:
categoryID catagoryName highercategoryID
8 Fragnance 0
99 Clothing 0
15 Armani Clothing 99
12 Armani Fragnance 8
102 Davidoff Fragnance 8
Expected result
ID ProductName Category CategoryTree
0 T-Shirt 15 Clothing > Armani Cloting
1 Aqua De Gio 12 Fragnance > Armani Fragnance
2 Jacket 15 Clothing > Armani Cloting
3 Hot Water 13 Fragnance > Davidoff Fragnance
For example take the T-Shirt from the products table
its category is 15.
go for the categories table and see where categoryID=15
look at the highercategoryID if its = 0 stop, if not then take its value 99
look for 99 in the categoryID column, the higher category now is 0 so stop.
based on the above I need to get "Clothing > Armani Clothing".
I am new to SQL queries and here is my first try
select
x.*,
x.p1 + isnull((' > ' + x.c1), '') + isnull((' > ' + x.c2), '') as CategoryTree
from
(select
RP.categoryid as catid,
RP.catagoryName as p1,
R1.catagoryName as c1,
R2.catagoryName as c2
from
categories as RP
left outer join
categories as R1 on R1.highercategoryid = RP.categoryid
left outer join
categories as R2 on R2.highercategoryid = R1.categoryid
left outer join
categories as R3 on R3.highercategoryid = R2.categoryid
where
RP.highercategoryid != 0 ) x
I am not sure how to stop the joining when I find the 0 value in the higher category, and how to join the products on their categories, and is there a dynamic way without using a lot of joins?
Here it goes:
With CTE (CatID, CatName, HigherCatID) AS
(
SELECT categoryID, CAST(catagoryName AS VARCHAR(1000)), highercategoryID
FROM CATEGORIES
UNION ALL
SELECT C.categoryID, CAST(CTE.CatName + ' > ' + C.catagoryName AS VARCHAR(1000)), CTE.HigherCatID
FROM CATEGORIES C
INNER JOIN CTE ON C.HigherCategoryID = CTE.CatID
)
SELECT P.ID, P.ProductName, Cte.CatID, CTE.CatName
FROM CTE INNER JOIN PRODUCTS P
ON (CatID = P.Category)
WHERE CTE.HigherCatID=0
you got a SQLFiddle Here
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