How to sum and subtract values using update with group by Sql query? - sql

MyTable:
item_name Qty item_area
Belts 2 India
Shoes 20 US
T-Shirt 10 India
T-Shirt 12 US
T-Shirt 25 US
I get this by select group by query
SELECT item_name, Sum(item_qty) as Qty, item_area
FROM dbo.item_stocks
group by item_area, item_name
and my output is below:
item_name Qty item_area
Belts 2 India
Shoes 20 US
T-Shirt 10 India
T-Shirt 37 US
Now i need to subtract and update .How can i do this ?
For eg. i want to subtract 5 T-Shirt ,it will update in MyTable?
T-shirt=37-5=32
how can i update in MyTable?

You can try to use ROW_NUMBER window function to choose any one row to subtract.
;WITH CTE AS (
SELECT *,ROW_NUMBER() over(PARTITION BY item_name,item_area order by Qty desc)rn
FROM item_stocks
)
update CTE
set Qty = Qty - 5
where rn = 1 and item_name = 'T-Shirt' and item_area = 'US'
SELECT item_name, Sum(Qty) as Qty, item_area
FROM item_stocks
group by item_area, item_name

just add a column which denotes in/Out, say INOUT
don't update row, just add new row for the stock sale.
Here,
INOUT = 1 denotes IN and 2 denotes OUT
table structure like
item_name Qty item_area INOUT
Belts 2 India 1
Shoes 20 US 1
T-Shirt 10 India 1
T-Shirt 12 US 1
T-Shirt 25 US 1
T-Shirt 5 US 2
now your query looks like that
SELECT item_name,
Sum(case when INOUT = 1 then item_qty else (0-item_qty) end) as Qty,
item_area
FROM dbo.item_stocks
group by item_area, item_name

Related

How to find out first product item client purchased whose bought specific products?

I want to write a query to locate a group of clients whose purchased specific 2 product categories, at the same time, getting the information of first transaction date and first item they purchased. Since I used group by function, I could only get customer id but not first item purchase due to the nature of group by. Any thoughts to solve this problem?
What I have are transaction tables(t), customer_id tables(c) and product tables(p). Mine is SQL server 2008.
Update
SELECT t.customer_id
,t.product_category
,MIN(t.transaction_date) AS FIRST_TRANSACTION_DATE
,SUM(t.quantity) AS TOTAL_QTY
,SUM(t.sales) AS TOTAL_SALES
FROM transaction t
WHERE t.product_category IN ('VEGETABLES', 'FRUITS')
AND t.transaction_date BETWEEN '2020/01/01' AND '2022/09/30'
GROUP BY t.customer_id
HAVING COUNT(DISTINCT t.product_category) = 2
**Customer_id** **transaction_date** **product_category** **quantity** **sales**
1 2022-05-30 VEGETABLES 1 100
1 2022-08-30 VEGETABLES 1 100
2 2022-07-30 VEGETABLES 1 100
2 2022-07-30 FRUITS 1 50
2 2022-07-30 VEGETABLES 2 200
3 2022-07-30 VEGETABLES 3 300
3 2022-08-01 FRUITS 1 50
3 2022-08-05 FRUITS 1 50
4 2022-08-07 FRUITS 1 50
4 2022-09-05 FRUITS 2 100
In the above, what I want to show after executing the SQL query is
**Customer_id** **FIRST_TRANSACTION_DATE** **first_product_category** **TOTAL_QUANTITY** **TOTAL_SALES**
2 2022-07-30 VEGETABLES, FRUITS 4 350
3 2022-07-30 VEGETABLES 5 400
Customer_id 1 and 4 will not be shown as they only purchased either vegetables or fruits but not both
Check now, BTW need find logic with product_category
select CustomerId, transaction_date, product_category, quantity, sales
from(
select CustomerId, transaction_date, product_category , sum(quantity) over(partition by CustomerId ) as quantity , sum(sales) over(partition by CustomerId ) as sales, row_number() over(partition by CustomerId order by transaction_date ASC) rn
from(
select CustomerId, transaction_date, product_category, quantity, sales
from tablee t
where (product_category = 'FRUITS' and
EXISTS (select CustomerId
from tablee tt
where product_category = 'VEGETABLES'
and t.CustomerId = tt.CustomerId)) OR
(product_category = 'VEGETABLES' and
EXISTS (select CustomerId
from tablee tt
where product_category = 'FRUITS'
and t.CustomerId = tt.CustomerId)))x)over_all
where rn = 1;
HERE is FIDDLE

Select the best selling product ID

What if I have table like this and I want to select the best selling product_id.
id
transaction_id
product_id
qty_sold
1
21
2
5
2
22
3
2
3
23
4
2
3
24
2
1
3
25
2
4
I want the best selling product_id with the highest qty_sold
Using SQLS, you can group by the productID, add up the number of sold, and order by the total descending. If we also take the minimum transaction ID per product, if two products come out to have the same total qty, we can take the minimum tran ID to split the tie
SELECT TOP 1 product_id, SUM(qty_sold) as sellcount, MIN(transaction_id) as firsttran
FROM t
GROUP BY product_id
ORDER BY SUM(qty_sold) DESC, MIN(transaction_id)
Once you're happy the sums are right etc, you can remove the , SUM(qty_sold) as sellcount, MIN(transaction_id) from the SELECT if you want/if you only need the prod ID

Access sql Moving Average of Top N With 2 criterias

I have been searching the forum and found a single post that is a little smilair to my problem here: Calculate average for Top n combined with SQL Group By.
My situation is:
I have a table tblWEIGHT that contains: ID, Date, idPONR, Weight
I have a second table tblSALES that contains: ID, Date, Sales, idPONR
I have a third table tblPONR that contains: ID, PONR, idProduct
And a fouth table tblPRODUCT that contais: ID, Product
The linking:
tblWEIGHT.idPONR = tblPONR.ID
tblSALES.idPONR = tblPONR.ID
tblPONR.idProduct = tblPRODUCT.ID
The maintable of my query is tblSALES. I want to all my sales listed, with the moving average of the top5
weights of the PRODUCT where the date of the weight is less than the sales date, and the product is the same as the sold product. Its IMPORTANT that the result isn't grouped by the date. I need all the records of tblSALES.
i have gotten as far as to get the top 1 weight, but im not able to get the moving average instread.
The query that gest the top 1 is the following, and i am guessing that the query i need is going to look a lot like it.
SELECT tblSALES.ID, tblSALES.Dato, tblPONR.idPRODUCT,
(
SELECT top 1 Weight FROM tblWEIGHT INNER JOIN tblPONR ON tblWeight.idPONR = tblPONR.ID
WHERE tblPONR.idPRODUCT = idPRODUCT AND
SALES.Date > tblWEIGHT.Date
ORDER BY tblWEIGHT.Date desc
) AS LatestWeight
FROM tblSALES INNER JOIN VtblPONR ON tblSALES.idPONR = tblPONR.ID
this is not my exact query since im danish and i wouldnt make sense. I know im not supposed to use Date as a fieldname.
i imagine the filan query would be something like:
SELECT tblSALES.ID..... avg(SELECT TOP 5 weight .........)
but doing this i keep getting error at max 1 record can be returned by this subquery
Final Question.
How do i make a query that creates a moving average of the top 5 weights of my sold product, where the date of the weight is earlier than the date i sold the product?
EDIT Sampledata:
DATEFORMAT: dd/mm/yyyy
tblWEIGHT
ID Date idPONR Weight
1 01-01-2020 1 100
2 02-01-2020 2 200
3 03-01-2020 3 200
4 04-01-2020 3 400
5 05-01-2020 2 250
6 06-01-2020 1 150
7 07-01-2020 2 200
tblSALES
ID Date Sales(amt) idPONR
1 05-01-2020 30 1
2 06-01-2020 15 2
3 10-01-2020 20 3
tblPONR
ID PONR(production Number) idProduct
1 2521 1
2 1548 1
3 5484 2
tblPRODUCT
ID Product
1 Bricks
2 Tiles
Desired outcome read comments for AvgWeight
tblSALES.ID tblSALES.Date tblSales.Sales(amt) AvgWeigt
1 05-01-2020 30 123 -->avg(top 5 newest weight of both idPONR 1 And 2 because they are the same product, and where tblWeight.Date<05-01-2020)
2 06-01-2020 15 123 -->avg(top 5 newest weight of both idPONR 1 And 2 because they are the same product, and where tblWeight.Date<06-01-2020)
3 10-01-2020 20 123 -->avg(top 5 newest weight of idPONR 3 since thats the only idPONR with that product, and where tblWeight.Date<10-01-2020)
Consider:
Query1
SELECT tblWeight.ID AS WeightID, tblWeight.Date AS WtDate,
tblWeight.idPONR, tblPONR.PONR, tblPONR.idProduct, tblWeight.Weight, tblSales.SalesAmt,
tblSales.ID AS SalesID, tblSales.Date AS SalesDate
FROM (tblPONR INNER JOIN tblWeight ON tblPONR.ID = tblWeight.idPONR)
INNER JOIN tblSales ON tblPONR.ID = tblSales.idPONR;
Query2
SELECT * FROM Query1 WHERE WeightID IN (
SELECT TOP 5 WeightID FROM Query1 AS Dupe WHERE Dupe.idProduct = Query1.idProduct
AND Dupe.WtDate<Query1.SalesDate ORDER BY Dupe.WtDate);
Query3
SELECT Query2.SalesID, Query2.SalesDate, Query2.SalesAmt,
First(DAvg("Weight","Query2","idProduct=" & [idProduct] & " AND WtDate<#" & [SalesDate] & "#")) AS AvgWt
FROM Query2
GROUP BY Query2.SalesID, Query2.SalesDate, Query2.SalesAmt;

How to calculate Sum and Subtraction from two different table

I have two table "tbl_In_Details" and "tbl_Out_Details" Sample data for tbl_In_Details
sample data for tbl_In_Details
ID Item_Name Rate Quantity Source_company
1 wire 10 4 2020-04-21 22:47:29.083
2 Tea 4 20 2020-04-21 22:47:52.823
Sample data for tbl_Out_Details
ID Item_Name Quantity Created_Date
1 wire 1 2020-04-21 22:48:48.233
2 wire 2 2020-04-21 22:50:16.367
3 Tea 2 2020-04-21 23:48:39.94
Now i want to calculate current stock i.e. (incoming - Outgoing) as Current_Stock
i tried in such a way but not getting proper record please guide me where i need to modify my query:
Select O.Item_Name,
sum(CAST(I.Quantity AS INT))as Incoming_Quantity ,
SUM(CAST(o.Quantity as int)) as Outgoing_Quantity ,
(sum(CAST(I.Quantity AS INT)) - SUM(CAST(o.Quantity AS INT))) As Current_Stock
from tbl_In_Details I inner join tbl_Out_Details O
ON I.Item_Name = o.Item_Name group by O.Item_Name
My output should be
Item_Name Incoming_Quantity Outgoing_quantity Current_Stock
Wire 4 3 1
Tea 20 2 18
Use union all and aggregation:
select item_name, sum(in_quantity) as in_quantity, sum(out_quantity) as out_quantity,
sum(in_quantity) - sum(out_quantity) as in_stock
from ((select item_name, quantity as in_quantity, 0 as out_quantity
from incoming
) union all
(select item_name, 0, quantity
from outgoing
)
) io
group by item_name;

Sql Cleanse to one row

I am struggling with the solution to a query and any help would be greatly appreciated, I end up tying myself In knots with temptables and I'm sure there must be an easier way.
I have a database currently producing the below results - this is as it comes with no joins or production prior.
Acc No | prod No | Product Type | product Cost
12345678 1 Red Toy £100
12345678 2 Blue Toy £150
12345678 3 White Toy £300
12398654 1 White Toy £300
12398765 1 Red Toy £100
I only want one row per account number but don't want to lose the information. I would also like some sums. The below should hopefully show what I mean though there would be more columns:
Acc No | Prod total | cost | Prod1type | Prod1cost |prod2typ
12345678 3 £550 Red Toy £100 BlueToy
12398654 1 £300 White Toy £300 Null
I hope this explains it. I'm aware I would end up with many more columns but it would make my life so much easier.
Any help would be hugely appreciated,
Thanks in advance,
With out considering adding ProdType you could use this query.
Assume also there is only 1 product per line in table.
select acc_no, count(*) as prod_total, sum(cost) as total_cost
from table
group by acc_no
order by acc_no asc
to get all ProdType for a coresponding acc_no you could use
select distinct prodtype
from table
where acc_no='exact_number'
You can use multiple case statements to get your expected output.
Create sample data:
select 12345678 as Accno , 1 as prodno, 'Red Toy' as Producttype , 100 as Cost into #temp union all
select 12345678 as Accno , 2 as prodno, 'Blue Toy' as Producttype , 150 as Cost union all
select 12345678 as Accno , 3 as prodno, 'White Toy' as Producttype , 300 as Cost union all
select 12398654 as Accno , 1 as prodno, 'White Toy' as Producttype , 300 as Cost union all
select 12398765 as Accno , 1 as prodno, 'Red Toy' as Producttype , 100 as Cost
Query:
select accno, count(distinct prodno) Prodtotal, sum(cost) totalCost, max(case when prodno = 1 then Producttype end ) Product1type,
sum (case when prodno = 1 then cost end) Product1cost, max(case when prodno = 2 then Producttype end ) Product2type,
sum (case when prodno = 2 then cost end) Product2cost,max(case when prodno = 3 then Producttype end ) Product3type,
sum (case when prodno = 3 then cost end) Product3cost from #temp
group by accno
Output:
Formatting might be little bit different, but I assume this is your expected output.
accno Prodtotal totalCost Product1type Product1cost Product2type Product2cost Product3type Product3cost
12345678 3 550 Red Toy 100 Blue Toy 150 White Toy 300
12398654 1 300 White Toy 300 NULL NULL NULL NULL
12398765 1 100 Red Toy 100 NULL NULL NULL NULL