Sum of rows in SQL with GROUP BY - sql

I am having a table with data like:
ID OrderId TAX% Quantity UnitCost
1 5 28 2 1280
2 5 18 1 1180
I want the output like:
ORDERID TaxableValue TaxValue
5 3000 740
How can I achieve this? I tried with:
SELECT orderid,
ROUND((SUM(UnitCost*Quantity)*TAX)/(100+TAX),2) AS taxValue,
ROUND(SUM(unitCost*quantity)-ROUND((SUM(UnitCost*Quantity)*TAX)/(100+TAX),2),2) AS taxableValue
FROM table1
GROUP BY OrderId;
But the query above is not working.
Sorry all, That is the Tax percentage. This is the new Updated Query. Please consider this.

Pretty sure it is as simple as doing a little math.
select OrderID
, TaxableValue = SUM(UnitCost - TAX)
, TaxValue = SUM(TAX * Quantity)
from YourTable
group by OrderID
EDIT: The math was slightly off on the TaxableValue
For those who want proof that this works.
declare #Something table
(
ID int
, OrderId int
, TAX int
, Quantity int
, UnitCost int
)
insert #Something values
(1, 5, 28, 2, 228)
, (2, 5, 18, 1, 118)
select OrderID
, TaxableValue = SUM(UnitCost - TAX)
, TaxValue = SUM(TAX * Quantity)
from #Something
group by OrderID

This is how it can be done.
SELECT
orderid,
sum(unitcost*quantity) - sum(tax*quantity) as taxablevalue,
sum(tax*quantity) as taxvalue
FROM table1
GROUP BY OrderId;

select OrderId
, SUM((unitcost * quantity * tax)/(100+tax)) as TaxValue
, SUM(unitcost * quantity)-SUM((unitcost * quantity * tax)/(100+tax)) as taxableValue
from table1
group by OrderId

Related

How to value cost of sales using FIFO in SQL Server

I want value the cost of goods sold using the FIFO method.
I know how many beers I sold. Based on my price I bought those beers at, what is the cost of those sales? So, my sales of 7 Peronis are valued at £1.70 -- based on the FIFO valuation method.
How do I calculate in SQL Server.
I am going to be working this out for many products and from many branches at the same time, so I would like to use a method that does not involve cursors (or any other types of loops).
-- SETUP
DROP TABLE IF EXISTS #Deliveries;
CREATE TABLE #Deliveries (DeliveryDate DATE, ProductCode VARCHAR(10), Quantity INT, Cost DECIMAL(6,2));
INSERT INTO #Deliveries (DeliveryDate, ProductCode, Quantity, Cost)
VALUES
('2020-11-23', 'PERONI', 2, 0.20), ('2020-11-24', 'PERONI', 4, 0.30), ('2020-11-25', 'PERONI', 7, 0.10),
('2020-11-23', 'BUDWEISER', 5, 0.20), ('2020-11-24', 'BUDWEISER', 5, 0.50), ('2020-11-25', 'BUDWEISER', 4, 0.80);
DROP TABLE IF EXISTS #StockResults;
CREATE TABLE #StockResults (ProductCode VARCHAR(10), SalesQty INT, CostOfSalesValue DECIMAL(6,2));
INSERT INTO #StockResults (ProductCode, SalesQty)
VALUES ('PERONI', 7), ('BUDWEISER', 4);
SELECT * FROM #Deliveries;
SELECT * FROM #StockResults;
-- DESIRED RESULT
/*
ProductCode SalesQty CostOfSalesValue
PERONI 7 1.70
BUDWEISER 4 0.80
*/
This is probably not very efficient but it shows you one way in which this can be achieved which should help you come up with your finished solution. I would imagine that there needs to be a lot more complexity built into this process to account for things like stock wastage, but I'll leave that up to you:
Query
-- SETUP
declare #Deliveries table (DeliveryDate date, ProductCode varchar(10), Quantity int, Cost decimal(6,2));
insert into #Deliveries (DeliveryDate, ProductCode, Quantity, Cost) values ('2020-11-23', 'PERONI', 2, 0.20), ('2020-11-24', 'PERONI', 4, 0.30), ('2020-11-25', 'PERONI', 7, 0.10),('2020-11-23', 'BUDWEISER', 5, 0.20), ('2020-11-24', 'BUDWEISER', 5, 0.50), ('2020-11-25', 'BUDWEISER', 4, 0.80);
declare #StockResults table (ProductCode varchar(10), SalesQty int);
insert into #StockResults (ProductCode, SalesQty) values ('PERONI', 7), ('BUDWEISER', 4);
-- QUERY
with r as
(
select d.ProductCode
,d.DeliveryDate
,d.Quantity
,d.Cost
,isnull(sum(d.Quantity) over (partition by d.ProductCode order by d.DeliveryDate rows between unbounded preceding and 1 preceding),0) as RunningQuantityStart
,sum(d.Quantity) over (partition by d.ProductCode order by d.DeliveryDate) as RunningQuantityEnd
from #Deliveries as d
)
select r.ProductCode
,s.SalesQty
,sum(case when r.RunningQuantityEnd >= s.SalesQty
then (s.SalesQty - r.RunningQuantityStart) * r.Cost
else (r.RunningQuantityEnd - r.RunningQuantityStart) * r.Cost
end
) as CostOfSalesValue
from r
join #StockResults as s
on r.ProductCode = s.ProductCode
and r.RunningQuantityStart < s.SalesQty
group by r.ProductCode
,s.SalesQty;
##Output
+-------------+----------+------------------+
| ProductCode | SalesQty | CostOfSalesValue |
+-------------+----------+------------------+
| BUDWEISER | 4 | 0.80 |
| PERONI | 7 | 1.70 |
+-------------+----------+------------------+
Below query might help you:
declare #maxQty int
select #maxQty = max(SalesQty) from #StockResults
;WITH AllNumbers AS
(
SELECT 1 AS Number
UNION ALL
SELECT Number+1 FROM AllNumbers WHERE Number < #maxQty
)
select ProductCode, SalesQty, SUM(Cost) as CostOfSalesValue from
(
SELECT SR.ProductCode, SR.SalesQty, DLM.RN, DLM.Cost FROM #StockResults SR
outer apply
(
select ROW_NUMBER()OVER (order by DeliveryDate asc) as RN, Dl.Cost from #Deliveries Dl
inner join AllNumbers AL on AL.Number <= Dl.Quantity
where Dl.ProductCode = SR.ProductCode
) as DLM
) result
where RN <= SalesQty
group by ProductCode, SalesQty

Retrieve specific value if set, or general if not

I have to write a query which will import some data from table. Table structure is like:
Item_ID
Plant
Price
I have second table with
Item_ID
Plant
Second table is a key, and I have to match rows from first table to get valid price. Seems to be easy, however:
In first table column plant might determinate specific plant, or have value 'ALL'. What I want to do is retrieve price for given plant, if it is set, or get price for value 'ALL' if there is no row for given plant. In other words:
If first.Plant = second.Plant
return price
Else If first.Plant = 'ALL'
return price
Else
return NULL
I can't use simple ON first.Plant = second.Plant OR first.Plant = 'ALL', because there might be two rows: one for given plant and second for rest with value 'ALL'. I need to return only first price in that case. E.g.
Item_ID | Plant | Price
2 | M1 | 10,0
2 | All | 12,0
1 | All | 9,0
In that case for Item_ID = 2 and Plant = M1 the only valid price = 10, but for Item_ID = 2 and Plant = M2 price = 12, and for any Item_ID = 1 price = 9
I hope You understood something after my explanation ;)
Using ROW_Number and a Common Table Expression you can ensure that ROW_NUMBER is partitioned by Item_ID and Plant and ordered such that if there are two rows then 'All' is second. You then simple select the rows with a row number = 1:
Setup
CREATE TABLE #Price
(
Item_ID int,
Plant Varchar(20),
Price Decimal(6,2)
)
CREATE TABLE #Plant
(
Item_ID int,
Plant VARCHAR(20)
)
INSERT INTO #Price
VALUES (2, 'M1', 10.0),
(2, 'All', 12.0),
(1, 'All', 9.0)
INSERT INTO #Plant
VALUES (2, 'M1'),
(2, 'M2'),
(1, 'M1'),
(1, 'M2')
Here's the query for SQL Server >= 2012
;WITH CTE
AS
(
SELECT PL.Item_ID, PL.Plant, PR.PRice, ROW_NUMBER() OVER (PARTITION BY Pl.Item_ID, Pl.Plant ORDER BY IIF(PR.Plant = 'All', 1, 0)) AS RN
FROM #Plant PL
INNER JOIN #Price PR
ON PL.Item_Id = PR.Item_Id AND (PL.Plant = PR.Plant OR PR.Plant = 'ALL')
)
SELECT Item_Id, Plant, Price
FROM CTE
WHERE RN = 1
And here's a version using CASE which will work for all SQL Server >= 2008 R2
;WITH CTE
AS
(
SELECT PL.Item_ID, PL.Plant, PR.PRice, ROW_NUMBER() OVER (PARTITION BY Pl.Item_ID, Pl.Plant ORDER BY CASE WHEN PR.Plant = 'All' Then 1 Else 0 End) AS RN
FROM #Plant PL
INNER JOIN #Price PR
ON PL.Item_Id = PR.Item_Id AND (PL.Plant = PR.Plant OR PR.Plant = 'ALL')
)
SELECT Item_Id, Plant, Price
FROM CTE
WHERE RN = 1

SQL Server query to get the total for each row

I have two tables InvoiceLine and Discount:
I need to get a result set which includes invoice Line items with the total (SUM) of discounts in the discount table like below:
How can I achieve this using only one query?
DECLARE #InvoiceLine TABLE
(
InvoiceHeaderID INT ,
InvoiceLineNo INT ,
ProductCode VARCHAR(5) ,
Price MONEY
);
INSERT INTO #InvoiceLine
VALUES ( 1, 1, 'AB001', 1200 ),
( 2, 1, 'AC002', 1525 );
DECLARE #Discount TABLE
(
InvoiceHeaderID INT ,
InvoiceLineNo INT ,
DiscountCategory VARCHAR(10) ,
discountValue MONEY
);
INSERT INTO #Discount
VALUES ( 1, 1, 'SalesDisc', 120 ),
( 1, 1, 'FixedOffer', 100 ),
( 2, 1, 'SalesDisc', 152.50 );
SELECT l.InvoiceHeaderID ,
l.InvoiceLineNo ,
l.ProductCode ,
l.Price ,
ISNULL(SUM(d.discountValue),0) [TotalDiscount]
FROM #InvoiceLine l
LEFT JOIN #Discount d ON d.InvoiceHeaderID = l.InvoiceHeaderID
AND d.InvoiceLineNo = l.InvoiceLineNo
GROUP BY l.InvoiceHeaderID ,
l.InvoiceLineNo ,
l.ProductCode ,
l.Price;
Result
SELECT
A.InvoiceHeaderID, A.InvoiceLineNo, ProductCode, Price, SUM(DiscountValue) as TotDiscount
FROM
InvoiceLine A, Discount B
WHERE
A.InvoiceHeaderID = B.InvoiceHeaderID
AND A.InvoiceLineNo = B.InvoiceLineNo
GROUP BY
A.InvoiceHeaderID, A.InvoiceLineNo, ProductCode, Price
Order BY
A.InvoiceHeaderID, A.InvoiceLineNo
select
i.InvoiceHeaderId,
i.InvoiceLineNo,
i.ProductCode,
i.Price,
[TotDiscount]=isnull(d.TotDiscount)
from
[InvoiceLine] i
left join
[Discount] d on i.InvoiceHeaderId=d.InvoiceHeaderId and i.InvoiceLineNo=d.InvoiceLineNo
group by
i.InvoiceHeaderId,
i.InvoiceLineNo,
i.ProductCode,
i.Price
SELECT
InvoiceLine .InvoiceHeaderID, InvoiceLine .InvoiceLineNo, ProductCode, Price, SUM(DiscountValue) as TotDiscount
FROM
InvoiceLine, Discount
WHERE
InvoiceLine .InvoiceHeaderID = Discount .InvoiceHeaderID AND A.InvoiceLineNo = Discount .InvoiceLineNo
GROUP BY InvoiceLine .InvoiceHeaderID, InvoiceLine .InvoiceLineNo, ProductCode, Price
Order BY InvoiceLine .InvoiceHeaderID, InvoiceLine .InvoiceLineNo

Query matching stock trading buyers/sellers based on conditions

I'm trying to create a stored procedure that matches buyers and sellers for a fake stock market program. I eventually I'd like to use this to populate a transaction table to finalize peoples orders. This would also be in a SQL Server Agent Job. Here's the table I have:
Id UserId Type QtyRemaining Price CreatedOn
1 3 BUY 50 1.00 2012-09-09 05:25:48.4470000
2 6 BUY 50 1.00 2012-09-09 19:25:34.4300000
3 5 SELL 30 1.00 2012-09-09 19:22:59.5900000
4 3 SELL 50 0.90 2012-09-09 06:39:34.9100000
5 2 SELLALL 50 1.00 2012-09-09 04:10:01.8400000
There are several conditions that need to be satisfied to make these matches:
A buyer must look for a seller that has >= amount of shares that the buyer wants if its a 'SELL' order. If its a 'SELLALL' order then the Qty must be equal for the buyer to buy the stock. E.g. The seller must be selling 50 shares and the buyer MUST be buying 50 shares at the same price or lower.
A buyer wants the minimum price for the stock.
If there are multiple sellers with the conditions above a buyer takes the oldest selling stock first after the minimum price.
So the pairs of traders would be #1 and #4, #2 and #5. Therefore #3 would still be pending.
Here's the code I was playing around with but I can't get it to match up properly with the minimum price and the oldest first:
select o.*, oa.*, r.* from [Order] o
join OrderActivity oa on o.Id = oa.OrderId
join (
select o2.Id, o2.VideoId, o2.UserId, oa2.Price, oa2.QtyRemaining, o2.[Type] from [Order] o2
join OrderActivity oa2 on o2.Id = oa2.OrderId
where o2.Type = 'buy' and oa2.Status = 'open'
) as r on (o.VideoId = r.VideoId and oa.Price <= r.Price and r.QtyRemaining = oa.QtyRemaining and o.UserId != r.UserId)
where (o.Type = 'sell' or o.Type = 'sellall') and oa.Status = 'open'
try this
Briefly ,
1.Rank buyer based on the createddate(named as stocks in the below query) 2.Rank seller based on the price,createddate(named as lowNoldstock)3.Get the matching rank
select stocks.*,lowNoldStock.*
from (select *,row_number() over(order by createdon) as buyerrank
from stocktable(nolock) where c='buy' ) stocks
inner join
(select *,row_number() over(order by price,createdon) as sellerrank
from stocktable(nolock) where [type]='sell' or [type]='sellall' ) lowNoldstock
on (stocks.qty<=lowNoldStock.qty and lowNoldStock.type='sell')
or (lowNoldStock.type='sellall' and stocks.qty=lowNoldStock.qty and stocks.price>=lowNoldStock.price)
where lowNoldStock.sellerrank=stocks.buyerrank
test script in sql fiddle ,for some reason it is showing partial result in sql fiddle
This works in my local database
You are welcome to play with this:
declare #Transactions as Table
( Id Int, UserId Int, Type VarChar(8), QtyRemaining Int, Price Money, CreatedOn DateTime )
insert into #Transactions ( Id, UserId, Type, QtyRemaining, Price, CreatedOn ) values
( 1, 3, 'BUY', 50, 1.00, '2012-09-09 05:25:48.447' ),
( 2, 6, 'BUY', 50, 1.00, '2012-09-09 19:25:34.430' ),
( 3, 5, 'SELL', 30, 1.00, '2012-09-09 19:22:59.590' ),
( 4, 3, 'SELL', 50, 0.90, '2012-09-09 06:39:34.910' ),
( 5, 2, 'SELLALL', 50, 1.00, '2012-09-09 04:10:01.840' )
-- Split the transactions into temporary working tables.
declare #Buyers as Table
( Id Int, UserId Int, Type VarChar(8), QtyRemaining Int, Price Money, CreatedOn DateTime )
declare #Sellers as Table
( Id Int, UserId Int, Type VarChar(8), QtyRemaining Int, Price Money, CreatedOn DateTime )
insert into #Buyers
select Id, UserId, Type, QtyRemaining, Price, CreatedOn
from #Transactions
where Type = 'BUY'
insert into #Sellers
select Id, UserId, Type, QtyRemaining, Price, CreatedOn
from #Transactions
where Type like 'SELL%'
-- Process the buy orders in the order in which they were created.
declare #BuyerId as Int = ( select top 1 Id from #Buyers order by CreatedOn )
declare #SellerId as Int
declare #Balance as Int
while #BuyerId is not NULL
begin
-- Pair a seller, if possible, with the current buyer.
; with Willard as (
select Row_Number() over ( order by S.Price, S.CreatedOn ) as Priority,
S.Id as S_Id, S.QtyRemaining as S_QtyRemaining,
B.QtyRemaining as B_QtyRemaining
from #Sellers as S inner join
#Buyers as B on B.Id = #BuyerId and
case
when S.Type = 'SELL' and B.QtyRemaining <= S.QtyRemaining then 1
when S.Type = 'SELLALL' and B.QtyRemaining = S.QtyRemaining then 1
else 0
end = 1
)
select #SellerId = S_Id, #Balance = S_QtyRemaining - B_QtyRemaining
from Willard
where Priority = 1
-- Display the result.
select #BuyerId as BuyerId, #SellerId as SellerId, #Balance as RemainingShares
-- Update the working tables.
if #Balance = 0
delete from #Sellers
where Id = #SellerId
else
update #Sellers
set QtyRemaining = #Balance
where Id = #SellerId
delete from #Buyers
where Id = #BuyerId
-- Find the next buy order.
set #BuyerId = ( select top 1 Id from #Buyers order by CreatedOn )
end
-- Display any unfilled orders.
select 'Unmatched Buy', *
from #Buyers
select 'Unmatched Sell', *
from #Sellers

Database Join Query

I am having a problem with a database join query and I am looking for someone to help me out.
Basically I've got two tables, Invoices and Receipts.
Invoices
Invoice ID
Amount
Date_Added
Receipts
ReceiptID
InvoiceID
Amount
Date_Added
The thing is that I need to produce a table like below, but I have multiple records in Receipts and I am pretty sure that the data is stored in a good way, just not exactly sure what the query would be.
InvoiceID RecieptID Amount Balance Date_Added
1 0 100.00 100.00 01.05.2012
1 1 100.00 0.00 02.05.2012
2 0 250.00 250.00 03.05.2012
3 0 100.00 350.00 04.05.2012
2 2 100.00 250.00 05.05.2012
Does this make sense? So it should be in date order. So effectively I can see line by line what is going on each date.
Setup:
USE tempdb;
GO
CREATE TABLE dbo.Invoices
(
InvoiceID INT,
Amount DECIMAL(12,2),
DateAdded SMALLDATETIME
);
CREATE TABLE dbo.Receipts
(
ReceiptID INT,
InvoiceID INT,
Amount DECIMAL(12,2),
DateAdded SMALLDATETIME
);
SET NOCOUNT ON;
INSERT dbo.Invoices SELECT 1, 100, '20120501'
UNION ALL SELECT 2, 250, '20120503'
UNION ALL SELECT 3, 100, '20120504';
INSERT dbo.Receipts SELECT 1, 1, 100, '20120502'
UNION ALL SELECT 2, 2, 100, '20120505';
Query:
;WITH x AS
(
SELECT InvoiceID, ReceiptID, Amount, DateAdded,
rn = ROW_NUMBER() OVER (ORDER BY DateAdded)
FROM
(
SELECT InvoiceID, ReceiptID = 0, Amount, DateAdded
FROM dbo.Invoices -- where clause?
UNION ALL
SELECT InvoiceID, ReceiptID, Amount, DateAdded
FROM dbo.Receipts -- where clause?
) AS y
),
z AS
(
SELECT xrn = x.rn, x.InvoiceID, x.ReceiptID, x.Amount, x.DateAdded,
PlusMinus = CASE WHEN x.ReceiptID > 0 THEN -x.Amount ELSE x.Amount END
FROM x LEFT OUTER JOIN x AS x2
ON x.rn = x2.rn + 1
)
SELECT InvoiceID, ReceiptID, Balance = (
SELECT SUM(COALESCE(PlusMinus, Amount))
FROM z AS z2
WHERE z2.xrn <= z.xrn
), Amount, DateAdded
FROM z
ORDER BY DateAdded;
Cleanup:
DROP TABLE dbo.Invoices, dbo.Receipts;
you can make a view that select data from the 2 tables like if the DB is oracle :
CREATE VIEW INVOICE_RECPT_VIEW as
select a.InvoiceID, b.RecieptID, b.Amount, b.Date_Added
from invoices a, receipts b
where a.InvoiceID = b.InvoiceID
order by Date_Added