Cumulative Cost Calculation in SQL Server - sql

I have a table for received material with unit price and a table with issued material without prices, I made a view to combine the two tables and show the tranasactions made for each material sorted by date, I need to calculate the unit price when the material was issued based on previous transactions, and show the cumulative cost for each material. I tried LAG, SUM OVER, INNER SELECT, but I can't get it right.
Received Material Table (MRV):
StoreNo
MRVNo
MatCode
TransDate
Qty
UPrice
TransCost
B1
444
122
1/1/2023
50
10
500
B1
555
122
1/5/2023
30
20
600
B1
556
122
1/6/2023
20
10
200
Issued Material Table (MIV):
StoreNo
MIVNo
MatCode
TransDate
Qty
B1
445
122
1/2/2023
30
B1
446
122
1/2/2023
20
B1
557
122
1/9/2023
10
B1
558
122
1/10/2023
40
I created a view that has all transactions together with cumulative balance and a row count that resets after each material (MatTrans):
RowNo
StoreNo
MatCode
TransDate
TransType
TransNo
Qty
Bal
UPrice
TransCost
CCost
1
B1
122
1/1/2023
RCV
444
50
50
10
500
500
2
B1
122
1/2/2023
ISS
445
-30
20
0
0
500
3
B1
122
1/2/2023
ISS
446
-20
0
0
0
500
4
B1
122
1/5/2023
RCV
555
30
30
20
600
1100
5
B1
122
1/6/2023
RCV
556
20
50
10
200
1300
6
B1
122
1/9/2023
ISS
557
-10
40
0
0
1300
7
B1
122
1/10/2023
ISS
558
-40
0
0
0
1300
I want something to do the below:
RowNo
StoreNo
MatCode
TransDate
TransType
TransNo
Qty
Bal
UPrice
TransCost
CCost
1
B1
122
1/1/2023
RCV
444
50
50
10
500
500
2
B1
122
1/2/2023
ISS
445
-30
20
10
-300
200
3
B1
122
1/2/2023
ISS
446
-20
0
10
-200
0
4
B1
122
1/5/2023
RCV
555
30
30
20
600
600
5
B1
122
1/6/2023
RCV
556
20
50
10
200
800
6
B1
122
1/9/2023
ISS
557
-10
40
16
-160
640
7
B1
122
1/10/2023
ISS
558
-40
0
16
-640
0
The price for received items is brought from the received material table.
The price for ISS rows is previous row CCost devided by previous row Bal.
and CCost is the summation of previous transactions.
I tried the below:
select MatTrans.RowNo, MatTrans.StoreNo, MatTrans.MatCode, MatTrans.TransDate, MatTrans.TransType, MatTrans.TransNo, MatTrans.Qty, MatTrans.Bal,
CASE WHEN TransType='RCV'
THEN UPrice
ELSE SUM(MatTrans.TransCost) OVER (PARTITION BY MatTrans.StoreNo, MatTrans.MatCode ORDER BY RowNo) / LAG(Bal) OVER (PARTITION BY MatTrans.StoreNo, MatTrans.MatCode ORDER BY RowNo)
END AS UPrice,
CASE WHEN TransType='RCV'
THEN
TransCost
ELSE
SUM(MatTrans.TransCost) OVER (PARTITION BY MatTrans.StoreNo, MatTrans.MatCode ORDER BY RowNo) / (LAG(Bal) OVER (PARTITION BY MatTrans.StoreNo, MatTrans.MatCode ORDER BY RowNo)) * Qty)
END AS TransCost,
CASE WHEN TransType='RCV'
THEN
LAG(CCost) OVER (PARTITION BY MatTrans.StoreNo, MatTrans.MatCode ORDER BY RowNo) + TransCost
ELSE
LAG(CCost) OVER (PARTITION BY MatTrans.StoreNo, MatTrans.MatCode ORDER BY RowNo) + (SUM(MatTrans.TransCost) OVER (PARTITION BY MatTrans.StoreNo, MatTrans.MatCode ORDER BY RowNo) / (LAG(Bal) OVER (PARTITION BY MatTrans.StoreNo, MatTrans.MatCode ORDER BY RowNo)) * Qty))
END AS CCost
FROM MatTrans
but it's not working because the rows calculations are happening during runtime, what is the right way to do this?

You can use recursive CTE to solve this, since as you say, the aggregation changes dynamically:
;WITH cte AS
(
SELECT *
FROM (
VALUES (1, N'B1', 122, N'1/1/2023', N'RCV', 444, 50, 50, 10, 500, 500)
, (2, N'B1', 122, N'1/2/2023', N'ISS', 445, -30, 20, 0, 0, 500)
, (3, N'B1', 122, N'1/2/2023', N'ISS', 446, -20, 0, 0, 0, 500)
, (4, N'B1', 122, N'1/5/2023', N'RCV', 555, 30, 30, 20, 600, 1100)
, (5, N'B1', 122, N'1/6/2023', N'RCV', 556, 20, 50, 10, 200, 1300)
, (6, N'B1', 122, N'1/9/2023', N'ISS', 557, -10, 40, 0, 0, 1300)
, (7, N'B1', 122, N'1/10/2023', N'ISS', 558, -40, 0, 0, 0, 1300)
) x (RowNo, StoreNo, MatCode, TransDate, TransType, TransNo, Qty, Bal, UPrice, TransCost, CCost)
)
, cte2 AS (
SELECT RowNo, StoreNo, MatCode, TransDate, TransType, TransNo, Qty, Bal, UPrice
, UPrice * QTY AS TranCost
, UPrice * QTY AS CCost
FROM cte c
WHERE rowno = 1
UNION ALL
SELECT row.RowNo, row.StoreNo, row.MatCode,row.TransDate, row.TransType, row.TransNo, row.Qty, row.Bal, row.Uprice
, row.QTY * CASE WHEN row.transtype = 'RCV' THEN row.Uprice ELSE prev.CCost / prev.bal END
, row.QTY * CASE WHEN row.transtype = 'RCV' THEN row.Uprice ELSE prev.CCost / prev.bal END + prev.CCost
FROM cte2 prev
INNER JOIN cte row
ON row.rowno = prev.rowno + 1
)
SELECT *
FROM cte2
OPTION (maxrecursion 0)
The performance might not be great though, since you're basically doing a row by row loop.

Related

SQL Splitting Rows Into Multiple Rows Based on Condition

I have the below table:
Account
Credit
Debt
Net
ItemCount
InvoiceNumber
AAA
1300
150
1150
2
10
AAA
500
50
450
12
20
AAA
1800
650
1150
29
30
No record can have a higher count than 10 items so anything over 10 must be split into multiples of 10 until the last remaining value (which could be less than 10)
I am trying to automate this in SQL and have not been able to come up with an idea that works, I would like something to look at the above table and spit out the following:
Account
Credit
Debt
Net
ItemCount
InvoiceNumber
AAA
1300
150
1150
2
10
AAA
500
50
450
10
20
AAA
500
50
450
2
30
AAA
1800
650
1150
10
10
AAA
1800
650
1150
10
20
AAA
1800
650
1150
9
30
Any thoughts on how can this be accomplished?
I would try to use a cursor to iterate through the records and generate as many inserts as you need based on the value that you have
If you work with SQL Server, this should do the trick for you
CREATE TABLE #Table1
(
[Account] varchar(3),
[Credit] int,
[Debt] int,
[Net] int,
[ItemCount] int,
[InvoiceNumber] int
);
INSERT INTO #Table1 ([Account], [Credit], [Debt], [Net], [ItemCount], [InvoiceNumber])
VALUES
('AAA', 1300, 150, 1150, 2, 10),
('AAA', 500, 50, 450, 12, 20),
('AAA', 1800, 650, 1150, 29, 30)
;
WITH cte_numbers([Account] , [Credit] , [Debt] , [Net] , [ItemCount] , [InvoiceNumber] , itemcountzero, currentitmecount)
AS
(
SELECT
*,
(itemcount % 10) AS itemcountzero,
(itemcount) AS currentitmecount
FROM
#Table1
UNION ALL
SELECT
t.[Account] , t.[Credit] , t.[Debt] , t.[Net] , t.[ItemCount] , t.[InvoiceNumber] , c.itemcountzero, (c.currentitmecount-10)
FROM
#Table1 t
INNER JOIN
cte_numbers c ON t.[InvoiceNumber] = c.[InvoiceNumber]
AND (c.currentitmecount-10) >= c.itemcountzero
-- AND (currentitmecount-10) > 0
)
SELECT
[Account] , [Credit] , [Debt] , [Net] , IIF(currentitmecount > 10, 10 , currentitmecount) as [ItemCount] , [InvoiceNumber]
FROM
cte_numbers
ORDER BY
[InvoiceNumber], currentitmecount DESC;

SQL: how to get counts from two groups that falls into one set of ranges

I have been struggling on how I can achieve the below output:
Background: Range is the number of items within ProductA and ProductB. They both have two different number of items. ProductA usually falls into different range category then ProductB.
I need to get one range for ProductA and ProductB.
ProductA
ProductB
Ranges
14
16
0-10
45
40
10-20
16
18
20-30
23
1
30-40
4
5
40-50
34
67
50-60
4
12
60-70
5
7
70-80
44
56
80-90
5
7
90-100
Table should be read as : e.g. ProductA has 34 number of items and falls into range 30-40, but ProductB (67 number of items) falls into different range in this case 60-70.
Here is the code - I need to find a way to get one range category(currently I have two separately: for ProductA and ProductB) that will be assigned for ProductA and ProductB and will give me one range for both:
WITH ProductA AS (
select
distinct m.ProductA as product_count_A,
case
when utilizationA <= 10 THEN '0-10'
when utilizationA <= 20
AND utilizationA > 10 THEN '10-20'
when utilizationA <= 30
AND utilizationA > 20 THEN '20-30'
when utilizationA <= 40
AND utilizationA > 30 THEN '30-40'
when utilizationA <= 50
AND utilizationA > 40 THEN '40-50'
when utilizationA <= 60
AND utilizationA > 50 THEN '50-60'
when utilizationA <= 70
AND utilizationA > 60 THEN '60-70'
when utilizationA <= 80
AND utilizationA > 70 THEN '70-80'
when utilizationA <= 90
AND utilizationA > 80 THEN '80-90'
when utilizationA <= 100
AND utilizationA > 90 THEN '90-100'
END "UtilizationA"
from
PRODUCTS_TABLE
),
ProductB AS (
Select
distinct ProductB as product_count_B,
CASE
when utilizationB <= 10 THEN '0-10'
when utilizationB <= 20
AND utilizationB > 10 THEN '10-20'
when utilizationB <= 30
AND utilizationB > 20 THEN '20-30'
when utilizationB <= 40
AND utilizationB > 30 THEN '30-40'
when utilizationB <= 50
AND utilizationB > 40 THEN '40-50'
when utilizationB <= 60
AND utilizationB > 50 THEN '50-60'
when utilizationB <= 70
AND utilizationB > 60 THEN '60-70'
when utilizationB <= 80
AND utilizationB > 70 THEN '70-80'
when utilizationB <= 90
AND utilizationB > 80 THEN '80-90'
when utilizationB <= 100
AND utilizationB > 90 THEN '90-100'
END "UtilizationB"
from
PRODUCTS_TABLE
)
SELECT
DISTINCT "UtilizationA",
"UtilizationB",
COUNT(ProductB.product_count_B) as ProductB_RES,
COUNT(ProductA.product_count_A) as ProductA_RES
from
ProductB,
ProductA
GROUP BY
"UtilizationA",
"UtilizationB";
As I have some background on Business Intelligence this looks similarly to problem I sometimes had on my reports: we tried to merge cpu p95 with cpu_max utilization to count how many hosts are eligible to one group/range set by p95 and separate count, but the same grouping, for cpu_max in other column.
Here's my take on this: http://sqlfiddle.com/#!18/babfb/1/0
(As I am not familiar with Oracle syntax I'll do it the MSSQL way, just for the notion of the idea)
With the input dataset in the format of:
host
p95
max_cpu
a
5
19
b
6
12
c
2
5
d
4
10
e
50
77
f
12
20
g
30
45
h
5
45
a
20
60
CREATE TABLE PRODUCTS_TABLE
("host" varchar(1), "p95" int, "max_cpu" int)
;
INSERT INTO PRODUCTS_TABLE
("host", "p95","max_cpu")
VALUES
('a', 5, 19),
('b', 6, 12),
('c', 2, 5),
('d', 4, 10),
('e', 50, 77),
('f', 12, 20),
('g', 30, 45),
('h', 5, 45),
('a', 20, 60)
;
I am preparing two sets of counts (ProductA_Count, ProductB_Count) and their assignements to appropriate ranges to finally JOIN them by the rank on the resulting query.
WITH ProductA AS (
select
host,
case
when p95 <= 10 THEN '0-10'
when p95 <= 20
AND p95 > 10 THEN '10-20'
(...your conditions here...)
when p95 <= 100
AND p95 > 90 THEN '90-100'
END "utilA"
from PRODUCTS_TABLE
group by host, p95
),
ProductA_Count AS (
select utilA, count(utilA) as 'utilA_ct'
from ProductA
group by utilA
),
ProductB AS (
select
host,
case
when max_cpu <= 10 THEN '0-10'
when max_cpu <= 20
(...your conditions here, duplicated, you may want to simplify it...)
when max_cpu <= 100
AND max_cpu > 90 THEN '90-100'
END "utilB"
from PRODUCTS_TABLE
),
ProductB_Count AS (
select utilB, count(utilB) as 'utilB_ct'
from ProductB
group by utilB
)
SELECT utilA_ct,utilB_ct,utilA
FROM ProductA_Count
LEFT OUTER JOIN ProductB_Count ON ProductA_Count.utilA=ProductB_Count.utilB
;
This results with
utilA_ct
utilB_ct
utilA
5
2
0-10
2
3
10-20
1
(null)
20-30
1
2
40-50
UNPIVOT the columns to rows and convert the utilization to ranges and then PIVOT back from rows to columns:
SELECT a_product AS productA,
b_product AS productB,
utilization
FROM (
SELECT type,
CASE
WHEN utilization <= 10 THEN '0-10'
WHEN utilization <= 20 THEN '10-20'
WHEN utilization <= 30 THEN '20-30'
WHEN utilization <= 40 THEN '30-40'
WHEN utilization <= 50 THEN '40-50'
WHEN utilization <= 60 THEN '50-60'
WHEN utilization <= 70 THEN '60-70'
WHEN utilization <= 80 THEN '70-80'
WHEN utilization <= 90 THEN '80-90'
ELSE '90-100'
END AS utilization,
product
FROM products_table
UNPIVOT (
(product, utilization) FOR type IN (
(producta, utilizationa) AS 'A',
(productb, utilizationb) AS 'B'
)
)
)
PIVOT (
COUNT(DISTINCT product) AS product
FOR type IN (
'A' AS a,
'B' AS b
)
)
Which, for the sample data:
CREATE TABLE products_table(producta, utilizationa, productb, utilizationb) AS
SELECT 1, 1, 1, 1 FROM DUAL UNION ALL
SELECT 1, 11, 2, 1 FROM DUAL UNION ALL
SELECT 1, 21, 1, 11 FROM DUAL UNION ALL
SELECT 1, 31, 1, 21 FROM DUAL UNION ALL
SELECT 1, 41, 1, 21 FROM DUAL UNION ALL
SELECT 1, 51, 1, 51 FROM DUAL UNION ALL
SELECT 1, 61, 1, 71 FROM DUAL UNION ALL
SELECT 1, 71, 1, 81 FROM DUAL;
Outputs:
PRODUCTA
PRODUCTB
UTILIZATION
1
2
0-10
1
1
10-20
1
1
20-30
1
0
30-40
1
0
40-50
1
1
50-60
1
0
60-70
1
1
70-80
0
1
80-90
db<>fiddle here

SQL cumulative based on condition

I need to take cumulative based on condition. If it is holiday I dont want to take cumulative.
If the row is the first row in date order and if that day is holiday then it should take daywiseplan value. For all subsequent rows, if IsHolday equals zero, accumulate DaywisePlan into the total. If IsHolday equals one, accumulate the value of DaywisePlan on the next row in date order where IsHolday equals zero
Date
DaywisePlan
IsHoliday
ExpectedOutput
7/1/2022
34
1
34
7/2/2022
34
1
34
7/3/2022
34
0
34
7/4/2022
34
0
68
7/5/2022
34
0
102
7/6/2022
34
0
136
7/7/2022
34
1
136
7/8/2022
34
1
136
7/9/2022
34
0
170
7/10/2022
34
0
204
7/11/2022
34
1
204
7/12/2022
34
0
238
in one Query id´ can't think of, but use a CTE , it is quite easy using The window Function SUM and FIRST_VALUE
if you have more month and want to have a SUM for all month sereately, you need to PARTITION both window function mothwise
WITH CTE AS
(SELECT
[Date], [DaywisePlan], [IsHoliday],
FIRST_VALUE([DaywisePlan]) OVER(PARTITION BY [IsHoliday] ORDER By [Date]) [First],
SUM(CASE WHEN [IsHoliday] = 0 THEN [DaywisePlan] ELSe 0 END) OVER(ORDER By [Date]) as [Sum]
FROM tab1)
SELECT [Date], [DaywisePlan], [IsHoliday]
,CASE WHEN [Sum] = 0 AND [IsHoliday] = 1 THEN [Sum]+ [first] ELSe [Sum] END as [Sum] FROM CTE
Date | DaywisePlan | IsHoliday | Sum
:---------------------- | ----------: | --------: | --:
2022-07-01 02:00:00.000 | 34 | 1 | 34
2022-07-02 02:00:00.000 | 34 | 1 | 34
2022-07-03 02:00:00.000 | 34 | 0 | 34
2022-07-04 02:00:00.000 | 34 | 0 | 68
2022-07-05 02:00:00.000 | 34 | 0 | 102
2022-07-06 02:00:00.000 | 34 | 0 | 136
2022-07-07 02:00:00.000 | 34 | 1 | 136
2022-07-08 02:00:00.000 | 34 | 1 | 136
2022-07-09 02:00:00.000 | 34 | 0 | 170
2022-07-10 02:00:00.000 | 34 | 0 | 204
2022-07-11 02:00:00.000 | 34 | 1 | 204
2022-07-12 02:00:00.000 | 34 | 0 | 238
db<>fiddle here
In the comments I proposed logic based on the first version of your expected results.
The expected results in the question as currently posed do not match that logic. Instead they seem to match this logic:
Do not accumulate DaywisePlan until arriving at the first row in order of date ascending where IsHolday equals zero. For that row and all subsequent rows, if IsHolday equals zero, accumulate DaywisePlan into the total.
You have also used an ambiguous date format which I infer (given the nature of your question) to be 'month/day/year', but could also be valid 'day/month/year' values. Here it happens to be the caes that the interpretation makes no difference to the ordering, but you should make it a habit of using non-ambiguous date formats like 'yyyyMMdd'.
In any case, here is a query which will produce the original expected results, and another query which will produce the new expected results. I have used similar CTE's for both to make the logic (and the difference between them) a little easier to read.
create table #mytable
(
[Date] date primary key,
DaywisePlan int,
IsHoliday bit,
ExpectedOutput int
);
set dateformat mdy;
-- original dataset
insert #mytable values
('7/1/2022', 34, 1, 34 ),
('7/2/2022', 34, 1, 34 ),
('7/3/2022', 34, 0, 68 ),
('7/4/2022', 34, 0, 102 ),
('7/5/2022', 34, 0, 136 ),
('7/6/2022', 34, 0, 170 ),
('7/7/2022', 34, 1, 170 ),
('7/8/2022', 34, 1, 170 ),
('7/9/2022', 34, 0, 204 ),
('7/10/2022', 34, 0, 238 ),
('7/11/2022', 34, 1, 238 ),
('7/12/2022', 34, 0, 272 );
-- logic producing original dataset
with working as
(
select [date],
DaywisePlan,
IsHoliday,
ExpectedOutput,
FullAccum = sum(DayWisePlan)
over (order by [date] rows unbounded preceding),
HoldayAccum = sum
(
iif(isHoliday = 1 and [date] != t.mindate, DayWisePlan, 0)
) over (order by [date] rows unbounded preceding)
from #mytable
cross join (select min([date]) from #myTable) t(mindate)
)
select [date],
daywiseplan,
isholiday,
expectedoutput,
CalculatedOutput = FullAccum - HoldayAccum
from working;
-- edited dataset
delete from #mytable;
insert #mytable values
('7/1/2022', 34, 1, 34 ),
('7/2/2022', 34, 1, 34 ),
('7/3/2022', 34, 0, 34 ),
('7/4/2022', 34, 0, 68 ),
('7/5/2022', 34, 0, 102 ),
('7/6/2022', 34, 0, 136 ),
('7/7/2022', 34, 1, 136 ),
('7/8/2022', 34, 1, 136 ),
('7/9/2022', 34, 0, 170 ),
('7/10/2022', 34, 0, 204 ),
('7/11/2022', 34, 1, 204 ),
('7/12/2022', 34, 0, 238 );
-- logic to produce edited dataset
with working as
(
select [date],
DaywisePlan,
IsHoliday,
ExpectedOutput,
firstNonHoliday = (select min([date]) from #myTable where IsHoliday = 0),
FullAccum = sum(DayWisePlan)
over (order by [date] rows unbounded preceding),
HoldayAccum = sum
(
iif(isHoliday = 1, DayWisePlan, 0)
) over (order by [date] rows unbounded preceding)
from #mytable
)
select [date],
daywiseplan,
isholiday,
expectedoutput,
CalculatedOutput = iif([date] < firstNonHoliday, daywiseplan, FullAccum - HoldayAccum)
from working;
If you just mean to say "ignore any holidays after the first non-holiday" then the logic can be significantly simplified (keeping the CTE for comparative purposes):
with working as
(
select [date],
DaywisePlan,
IsHoliday,
ExpectedOutput,
firstNonHoliday = (select min([date]) from #myTable where IsHoliday = 0),
FullAccum = sum(iif(isHoliday = 0, DayWisePlan, 0))
over(order by date rows unbounded preceding)
from #mytable
)
select [date],
daywiseplan,
isholiday,
expectedoutput,
CalculatedOutput = iif([date] <= firstNonHoliday, dayWisePlan, fullaccum)
from working;

SQL query to calculate interval discount

I have trouble understanding how I can solve this problem with a T-SQL query.
I have a price column and a volume column. In another table a have discounts at different levels of volume. So my discount table could have values as
(StartLevel, DiscountFactor)
(0, 1);
(25, 0.95);
(50, 0.90);
(100, 0.75)
What I want is to calculate a total price. If Volume is 35, I want it to multiply
Price x ((35-25) x 0.95 + (25-0) x 1)
If the volume is 200, it should be
Price x ((200-100) x 0.75 + (100-50) x .9+(50-25) x .95+(25) x 1)
Can anybody help me with a query that solves this?
This can help:
DECLARE #products TABLE
(
id INT ,
price MONEY ,
volume INT
)
DECLARE #discounts TABLE
(
id INT ,
Level INT ,
Factor MONEY
)
INSERT INTO #products
VALUES ( 1, 10, 35 ),
( 2, 15, 200 )
INSERT INTO #discounts
VALUES ( 1, 0, 1 ),
( 2, 25, 0.95 ),
( 3, 50, 0.90 ),
( 4, 100, 0.75 )
SELECT p.id, p.price * SUM(ca.m)
FROM #products p
CROSS APPLY ( SELECT * ,
Factor * ( -Level + LEAD(Level) OVER ( PARTITION BY p.id ORDER BY Level, d ) ) AS m
FROM ( SELECT 1 AS d ,
Level ,
Factor
FROM #discounts
WHERE Level < p.volume
UNION ALL
SELECT 2 AS d ,
p.volume ,
0
) t
) ca
GROUP BY p.id, p.price
Without grouping it returns:
id price volume d Level Factor m
1 10.00 35 1 0 1.00 25.00
1 10.00 35 1 25 0.95 9.50
1 10.00 35 2 35 0.00 NULL
2 15.00 200 1 0 1.00 25.00
2 15.00 200 1 25 0.95 23.75
2 15.00 200 1 50 0.90 45.00
2 15.00 200 1 100 0.75 75.00
2 15.00 200 2 200 0.00 NULL
Then just group by product and sum of m results in:
id Total
1 345.00
2 2531.25
For a given Volume and Price you can get the discount based on interval using LEAD which is available in SQL Server 2012+ onwards.
Sample Data
DECLARE #PriceTable TABLE(Volume INT,Price DECIMAL(9,2) )
DECLARE #Discount TABLE(StartLevel int, DiscountFactor DECIMAL(9,2))
INSERT INTO #PriceTable
VALUES(75, 20.5),
(150, 20),
(250, 20.5),
(0, 15);
INSERT INTO #Discount
VALUES(0, 1),
(25, 0.95),
(50, 0.90),
(100, 0.75);
Query
SELECT Volume,Price,FinalPrice
FROM #PriceTable P
CROSS APPLY(
SELECT SUM(CASE WHEN (MaxLevel >=StartLevel) THEN (MaxLevel-StartLevel) ELSE 0 END *DiscountFactor)*P.Price as FinalPrice
FROM
(
SELECT CASE WHEN LEAD(StartLevel)OVER(ORDER BY StartLevel) < P.Volume THEN LEAD(StartLevel)OVER(ORDER BY StartLevel) ELSE P.Volume END MaxLevel,StartLevel, DiscountFactor
FROM #Discount
) IQ
)T
Output
Volume Price FinalPrice
75 20.50 1460.6250
150 20.00 2625.0000
250 20.50 4228.1250
0 15.00 0.0000

Get data from SQL

Select
Id,
ROW_NUMBER() over(Order By(Select 1)) as SNo,
Tableno as 'Table Number',
convert(Date, tableorder.Date) as Date,
(LTRIM(RIGHT(CONVERT(VARCHAR(20), tableorder.Date, 100), 7))) as Time,
case
when TableOrder.Status = 1 then 'Open'
when TableOrder.Status = 0 then 'Close'
else 'Undifined'
end As 'Order Status',
KotNO as 'Kot Number',
(Select SUM(NetAmount)
from Bill
where Bill.OrderId = TableOrder.Id) as 'Total Amount'
from
TableOrder
Where
IsActive = '1' And IsDelete = '0'
This query returns this data:
Id SNo Table Number Date Time Order Status Kot Number Total Amount
318 1 1 4/3/2013 12:00AM Close 1218 270
319 2 1 4/3/2013 12:00AM Close 7581 335
320 3 1 4/3/2013 12:00AM Close 7582 110
321 4 1 4/3/2013 12:00AM Close 7585 165
323 5 4 4/3/2013 12:00AM Close 7586 80
324 6 1 4/3/2013 12:00AM Close 7587 45
325 7 3 4/3/2013 12:00AM Close 7588 150
326 8 1 4/3/2013 12:00AM Close 7589 145
327 9 1 4/3/2013 12:00AM Close 7590 70
328 10 4 4/3/2013 12:00AM Close 7591 120
I want to add 2 columns in this query for Vat 5% rate Amount = vat type id 2 and Vat 15% rate Amount = vat Type id 4
I have a second query like this in this query I use TableOrder id = 319
Select
Vt.Id, Vt.Description,
abs(Vt.Rate) as VRate,
Sum((( ItemPrice * Qty) - NetAmount)) as VatAmount
from
BillItem1 as B1
Left JOIN
ItemDescription ItD ON ItD.Id = B1.itemId
Left Join
VatType Vt on Vt.Id = ItD.TaxId
where
B1.IsActive = 1 and B1.IsDelete = 0
and B1.OrderId = 319
Group By
Vt.Id, Vt.Rate, Vt.Description
Order By
SUM((ItemPrice*Qty) - NetAmount) DESC
Output:
Id Description VRate VatAmount
2 Food 5 8.8094
4 Cold drinks 15 7.143
In this query get vat 5% for Vat type Id = 2 and 15 % for Vat type Id = 4 in above data 390 TableOrder Id Show Total Amount 270 and Vat Amount is (8.8094+7.143)
I want this amount show in below data in column
Table relation is
In Table BillItem Table I have Item Id and TableOrder Id
In Item Table I have VatTypeId
I think I see what you're after. Try the following...
SELECT
Id,
ROW_NUMBER() OVER(ORDER BY(SELECT 1)) as SNo,
Tableno AS 'Table Number',
convert(DateTime, tableorder.Date) AS [Date],
(LTRIM(RIGHT(CONVERT(VARCHAR(20), tableorder.Date, 100), 7))) as [Time],
CASE
WHEN TableOrder.Status = 1 THEN 'Open'
WHEN TableOrder.Status = 0 THEN 'Close'
ELSE 'Undefined'
END AS 'Order Status',
KotNO AS 'Kot Number',
SUM(Bill.NetAmount) AS 'Total Amount',
SUM(Bill.NetAmount) * 0.05 AS 'Tax 5',
SUM(Bill.NetAmount) * 0.15 AS 'Tax 15'
FROM
TableOrder INNER JOIN
Bill
ON TableOrder.Id = Bill.OrderId
WHERE
IsActive = '1' And
IsDelete = '0'
GROUP BY
Id,
Tableno,
TableOrder.[Date],
TableOrder.Status,
KotNO
See how that works for you.