SQL Bands - How to calculate - sql

I'm not quite sure what this type of query is, I thought perhaps a CASE statement or do I use BETWEEN? This is the data I have:
SKU
QTY
PRICE
SKU-1
1
12.50
SKU-1
5
11.00
SKU-1
10
10.00
SKU-1
15
8.50
It is basically what you would see on an ecommerce website when buying products. I want to fire in a qty & sku to this query (let's say 3), it would then know that 3 is between 1 and 5 and return me 37.50 or if a customer orders 12 it would return 120.00 etc.
As an update, this is how far I got:
DECLARE #sku nvarchar(50)
DECLARE #qty int
SET #sku = 'SKU-1'
SET #qty = 5
SELECT TOP 1 (price * #qty) FROM global_tier_pricing WHERE sku = #sku
This works until I send in a qty of 5, I would expect it to be (5*11) and be 55.00 but it says 62.50

Assuming you can only have one price for a given sku and qty, you can filter for the right price in the where clause before the arithmetic
declare #qty int=3;
declare #sku varchar(100)='SKU-1';
select #qty * price
from your_table
where sku=#sku and qty=(select max(qty) from your_table where qty<=#qty)

Related

Select rows where value between range and default to last row ID where value exceeded range

Here's an example table
ID
FROM
TO
MAX
100001
100.00
199.99
5
100002
200.00
299.99
4
100003
300.00
399.99
3
100004
400.00
499.99
2
This SQL works just fine. The result is row with row ID 10001.
DECLARE #VAL DECIMAL(6,2);
SET #VAL = 159.97
SELECT ID, FROM, TO, MAX
FROM [MyTable].[dbo].[MagicPlan]
WHERE #VAL BETWEEN FROM AND TO;
But, I can't figure out how to default to the last row where #VAL exceeded the range. As it stands currently, changing #VAL to 695.43 returns no rows. I want it to return row ID 10004. Does that make sense?
Use TOP 1 and first order by your desired criteria, then order by your secondary criteria
DECLARE #VAL decimal(6,2) = 159.97;
SELECT TOP 1 ID, [FROM], [TO], [MAX]
FROM [MyTable].[dbo].[MagicPlan]
ORDER BY
CASE WHEN #VAL BETWEEN [FROM] AND [TO] THEN 1 ELSE 0 END DESC
ID DESC;
Personally I would do it this way, because I find BETWEEN a bit unintuitive.
SELECT TOP 1 ID, [FROM], [TO], [MAX]
FROM [MyTable].[dbo].[MagicPlan]
ORDER BY
CASE WHEN [FROM] <= #VAL AND [TO] >= #VAL THEN 1 ELSE 0 END DESC
ID DESC;
DBFiddle.uk

SQL subset sum negative values

I have a table valued function that return the set of rows that matches a given sum, It works fine with positive values but not with negatives one.
Can someone modify this function to work with both positive and negative values (price field)
The function take a table with decimal values, then return the first combination of rows that match a given sum in the parameter :
For example if the #psum = 9 and the given table below :
n id price
1 1 4.00
2 2 4.00
3 3 5.00
4 4 6.00
5 5 8.00
The out put is :
select * from SubsetSum2(9)
n id price
3 3 5.00
2 2 4.00
alter FUNCTION [dbo].[SubsetSum2](#psum int )
RETURNS #tt table (n int,id int, price numeric(20,2))
AS
BEGIN
declare #t table (n int IDENTITY(1,1), id int, price numeric(20,2))
insert into #t -- note asc order of book prices
select 1, 4 union all
select 2, 4 union all
select 3, 5 union all
select 4, 6 union all
select 5, 8
declare #rows int, #p numeric(20,2), #sum numeric(20,2) set #sum= 9
delete from #t where price>#sum
set #p=(select sum(price) from #t)
if #p>= #sum
begin --1
set #rows=(select max(n) from #t)
declare #n int, #s numeric(20,2)
set #n=#rows+1 set #s=0
while 0=0
begin --2
while #n>1
begin --3
set #n=#n-1
if #s+(select price from #t where n=#n)<=#sum
and #s+(select sum(price) from #t where n<=#n)>=#sum
begin --4
set #s=#s+(select price from #t where n=#n)
insert into #tt select n, id, price from #t where n=#n
if #s=#sum return ;
end --4
end --3
set #n=(select min(n) from #tt)
set #s=#s-(select price from #tt where n=#n)
delete from #tt where n=#n
if #s=0 and (select sum(price) from #t where n<#n)<#sum break
end --2
end --1
return
END
Use Absolute function ABS(Price) for treating the negatives as positives

Display result of SQL arithmetic

I am fairly new to SQL. I have a table with several columns: item ID, purchased price and price sold. I need to write a sql statement to return the difference between the purchased price and price sold along with the item ID
Thanks!
Select itemID, purchasePrice - soldPrice
from myTable;
This will return all ItemID's, and the difference in the prices for each. You can add a where clause to filter.
Here is an example:
declare #itemID varchar(55), #purchasePrice float, #salePrice float
set #itemID = 'Shirt'
set #purchasePrice = 65.50
set #salePrice = 78.98
select #itemID, #salePrice - #purchasePrice

SQL Group By Sum of Column Value Not Fixed Value

I have a table of data like this:
CommonURN GiftAidAmount GA_Status
14013084 2.00 45
14637494 20.00 45
14637496 1.00 45
14637508 5.00 45
14637520 10.00 45
14637525 19.00 45
14637562 10.00 45
14637586 12.00 45
14637590 3.00 45
14637649 5.00 45
I want to group my rows into blocks totalling £1000 or less, where the GA_Status value equals 45.
What I have so far is this:
CREATE TABLE #Temp
(CommonURN int,
GiftAidAmount money,
RunningSum money,
GroupID int);
WITH cte
(commonURN,giftAidAmount,running_sum)
AS
(SELECT
c.commonURN,
c.giftAidAmount,
(select sum(c2.giftAidAmount)
from dbo.[Campaign_Data] as c2
where
GA_Status = 45 and
c2.commonURN <= c.commonURN)
FROM
[dbo].[Campaign_Data] c
WHERE GA_Status = 45)
INSERT INTO #Temp (CommonURN,GiftAidAmount,RunningSum,GroupID)
SELECT
commonURN,
giftAidAmount,
running_sum,
ceiling(running_sum/1000) as GroupID
FROM
cte
ORDER BY
commonURN
SELECT
GroupID,
COUNT(*) NumRows,
SUM(GiftAidAmount) TotalGiftAid
FROM
#Temp
GROUP BY GroupID
This works pretty well except that one of the groups in the result set is over £1000:
GroupID NumRows TotalGiftAid
1 100 999.83
2 107 999.57
3 91 990.82
4 114 1009.34
5 114 995.40
6 58 455.65
I don't understand why this is. Can anyone explain and help me fix it? Or suggest a better approach altogther?
You can get a running value with single table update using a variable, and condition the variable to reset when the running value exceeds 1000. You can also update a GroupID based on this. Here is how I would do it. I insert a bunch of random amounts here anywhere from 5 to 30. The larger the amounts, the more likely you will run into a scenario where the running value is well below 1000, but the next value puts the running value over 1000:
-- insert test data
declare #Campaign_Data table
(
GiftAidAmount money,
RunningValue money,
GroupID int
)
while (select count(*) from #Campaign_Data) < 2000
begin
insert into #Campaign_Data (GiftAidAmount)
values (round(rand()*25,2)+5)
end
-- update Running Value and GroupID; restart when amount exceeds 1000
declare #RunningValue money,
#GroupID int
set #RunningValue = 0
set #GroupID = 1
update #Campaign_Data
set
#GroupID = GroupID = case when #RunningValue + GiftAidAmount > 1000
then #GroupID + 1
else #GroupID
end,
#RunningValue = RunningValue = case when #RunningValue + GiftAidAmount > 1000
then GiftAidAmount
else #RunningValue + GiftAidAmount
end
-- return values grouped by GroupID
select
GroupID,
count(GroupID) NumRows,
sum(GiftAidAmount) TotalGiftAid
from #Campaign_Data
group by
GroupID
order by
GroupID
Try this:
SELECT
GroupID,
COUNT(*) NumRows,
SUM(GiftAidAmount) TotalGiftAid
FROM
#Temp
GROUP BY GroupID
HAVING SUM(GiftAidAmount) < 1000

SQL Query to retrieve the last records till the quantity purchased reaches the total quantity in stock

I have a table that have the ItemCode and Quantity in stock and another table that contains the purchases.
I want a query to get the Quantity in stock (ex. Qty = 5) and to take the purchase table to get the purchase invoices by descending order and take the Item Prices.
The Query has to keep retrieving records from the Purchase table according to the Quantity till we reach sum of Quantity in stock = 5.
ex.
**Purchase No ItemCode Qty Cost Price**
2 123 2 100
3 123 10 105
6 123 2 100
8 123 1 90
9 123 2 120
---------------------------------------------
**ItemCode Qty in Stock**
123 5
--------------------------------------------
In this example I want the query to retrieve for me the last 3 invoices (9,8 and 6) because the Qty (2+1+2 = 5)
Is there any suggestion .
Thank you in advance
This script should do the job.
/* SQL SCRIPT BEGIN */
create table #tmp (PurchaseNo int, ItemCode int, Qty int)
insert into #tmp (PurchaseNo, ItemCode, Qty)
select
p1.PurchaseNo, p1.ItemCode, sum(t.Qty) as Qty
from
Purchases p1
join
(
select
p2.PurchaseNo,
p2.ItemCode, p2.Qty
from
Purchases p2
) t on p1.PurchaseNo <= t.PurchaseNo and p1.ItemCode = t.ItemCode
group by p1.PurchaseNo, p1.ItemCode
order by p1.ItemCode, sum(t.Qty) asc
select * From #tmp
where
ItemCode = 123
and
Qty < 5
union
select top 1 * From #tmp
where
ItemCode = 123
and
Qty >= 5
order by PurchaseNo desc
drop table #tmp
/* SQL SCRIPT END */
Hi This can be the solution :
Here I have Used Result Table which will store the result.
I have used three tables Purchage(PurchageNo,ItemCode,Qty) , Stock(ItemCode,QtyInStock) and result(PurchageNo).
Full Workable Code is Here:
DECLARE #ItemCode int;
DECLARE #AvailableQty int;
SET #ItemCode = 123 ;
SET #AvailableQty = (select QtyInStock from Stock where ItemCode = #ItemCode);
SELECT
RowNum = ROW_NUMBER() OVER(ORDER BY PurchageNo),*
INTO #PurchageTemp
FROM Purchage
DECLARE #MaxRownum INT;
SET #MaxRownum = (select COUNT(*)from #PurchageTemp);
DECLARE #Iter INT;
SET #Iter = 1;
DECLARE #QtySum int=0;
DECLARE #QtySumTemp int=0;
DECLARE #CurrentItem int;
WHILE (#Iter <= #MaxRownum and #QtySum <= #AvailableQty)
BEGIN
set #QtySumTemp=#QtySum;
set #QtySumTemp = #QtySumTemp + (SELECT Qty FROM #PurchageTemp WHERE RowNum = #Iter and ItemCode=#ItemCode);
IF #QtySumTemp <= #AvailableQty
BEGIN
set #QtySum=#QtySumTemp;
set #CurrentItem= (SELECT PurchageNo FROM #PurchageTemp WHERE RowNum = #Iter and ItemCode=#ItemCode);
insert into [Result] values (#CurrentItem);
END
SET #Iter = #Iter + 1
END
DROP TABLE #PurchageTemp