Insert only up to a maximum number? - sql

I have an existing stored procedure that returns shopping cart items as individual rows, with one of the fields being Quantity of the said item.
In the case of a promotional offer, for example buy 2 and get another 2 free, then the same product will be returned as two rows, with a separate price and a quantity for each. In this case, 2 rows with a quantity of 2 in each row.
The procedure then checks each row against the quantity in stock, and alters the row if required by inserting into a new table for the updated order. Normally there are many items of each product in stock at a time, but in rare situations (normally for end run products) there could be fewer items in stock than the cart total should allow.
In this example, lets say there's 3 left. The procedure would compare each row as normal and see that there are 3 in stock and the row is only looking for 2. So each row passes the check even though we're one short.
The problem I have is, how can I keep a running total of how many items are in the cart when each row is compared individually? Can I declare and update an int value for every insert?
Edit Sample Data to illustrate issue:
Lets say that order number 1 returns the same product on 3 rows. Full price, discounted and free (probably not a realistic situation but one that my boss will want me to account for anyway)
LineID | ProductID | Price | Quantity | Note
001 | 00001 | 100 | 2 |
002 | 00001 | 50 | 2 |
003 | 00001 | 0 | 2 |
These rows are in a temp table item which is joined to the products products table by ProductID which would look something like this:
ProductID | BasePrice | QuantityAvailable
00001 | 100 | 3
Then the products are checked with this query:
UPDATE item
SET
note =
CASE WHEN product.quantityAvailable <= 0 THEN 'This item is no longer available'
WHEN item.quantity > product.quantityAvailable THEN 'Not Enough Stock'
WHEN product.quantityAvailable > item.Quantity THEN REPLACE(note, 'Not Enough Stock', '')
ELSE 'Not Enough Stock' END
, quantity =
CASE WHEN product.quantityAvailable < item.Quantity THEN product.quantityAvailable
ELSE item.Quantity END
OUTPUT inserted.ID, deleted.note, inserted.note, deleted.quantity, inserted.quantity,
INTO #modifiedItems
FROM item
INNER JOIN product ON product.ProductID = item.ID
The end goal is for the item table to be updated to reflect the maximum number available across all rows, with the result being:
LineID | ProductID | Price | Quantity | Note
001 | 00001 | 100 | 2 |
002 | 00001 | 50 | 1 | Not enough stock
003 | 00001 | 0 | 0 | Not enough stock
edit 2: electric boogaloo
I have attempted to use a local variable to calculate a running total, but this seems to jump straight to the total value. Example below:
DECLARE #runningTotalQuantity int = 0
UPDATE item
SET
note =
CASE WHEN product.quantityAvailable <= 0 THEN 'This item is no longer available'
WHEN item.quantity > product.quantityAvailable THEN 'Not Enough Stock'
WHEN product.quantityAvailable > item.Quantity THEN REPLACE(note, 'Not Enough Stock', '')
ELSE 'Not Enough Stock' END
, quantity =
CASE WHEN #runningTotalQuantity != 0 AND #runningTotalQuantity <= ItemLimits.limitedQty AND (#runningTotalQuantity + Item.Quantity) <= ItemLimits.limitedQty then Item.Quantity
WHEN (#runningTotalQuantity + Item.quantity) >= ItemLimits.limitedQty THEN (ItemLimits.limitedQty - #runningTotalQuantity) WHEN product.quantityAvailable < item.Quantity THEN product.quantityAvailable
ELSE item.Quantity END
, #runningTotalQuantity = #runningTotalQuantity + item.Quantity
OUTPUT inserted.ID, deleted.note, inserted.note, deleted.quantity, inserted.quantity,
INTO #modifiedItems
FROM item
INNER JOIN product ON product.ProductID = item.ID
But this has the following result:
LineID | ProductID | Price | Quantity | Note
001 | 00001 | 100 | 2 |
002 | 00001 | 50 | 6 |
003 | 00001 | 0 | 6 |

It is easy to calculate running total in SQL Server 2014, just use SUM() OVER (...). The ordering of results is important for the running total, I used LineID to order the rows. You can choose some other ordering that suits you.
The first CTE in the query below calculates running total for each product and the difference DiffQuantity tells us at which row the product is depleted.
The new value of Quantity is one of three possibilities:
1) If there is still enough stock, the Quantity doesn't change.
2) If there is no stock at all, the Quantity is zero.
3) There can be one row in between where Quantity decreases partially.
Finally, the source table is updated with new values of Quantity and Notes.
Run this query CTE-by-CTE and examine intermediate results to understand how it works.
Sample data
DECLARE #Items TABLE (LineID int PRIMARY KEY, ProductID int, Price money, Quantity int, Note nvarchar(4000));
INSERT INTO #Items (LineID, ProductID, Price, Quantity, Note) VALUES
(001, 00001, 100, 2, ''),
(002, 00001, 50, 2, ''),
(003, 00001, 0, 2, '');
DECLARE #Products TABLE (ProductID int PRIMARY KEY, BasePrice money, QuantityAvailable int);
INSERT INTO #Products (ProductID, BasePrice, QuantityAvailable) VALUES
(00001, 100, 3);
Query
WITH
CTE
AS
(
SELECT
I.LineID
,I.ProductID
,I.Price
,I.Quantity
,I.Note
,P.QuantityAvailable
,SUM(I.Quantity) OVER (PARTITION BY I.ProductID ORDER BY I.LineID
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS SumQuantity
,SUM(I.Quantity) OVER (PARTITION BY I.ProductID ORDER BY I.LineID
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
- P.QuantityAvailable AS DiffQuantity
FROM
#Items AS I
INNER JOIN #Products AS P ON P.ProductID = I.ProductID
)
,CTE2
AS
(
SELECT
LineID
,ProductID
,Price
,Quantity
,Note
,QuantityAvailable
,DiffQuantity
,CASE WHEN DiffQuantity > 0 THEN 'Not enough stock' ELSE '' END AS NewNote
,CASE WHEN DiffQuantity > 0
THEN
CASE WHEN Quantity > DiffQuantity
THEN DiffQuantity
ELSE 0 END
ELSE Quantity END AS NewQuantity
FROM CTE
)
UPDATE CTE2
SET
Quantity = NewQuantity
,Note = NewNote
;
Result
SELECT * FROM #Items;
+--------+-----------+--------+----------+------------------+
| LineID | ProductID | Price | Quantity | Note |
+--------+-----------+--------+----------+------------------+
| 1 | 1 | 100.00 | 2 | |
| 2 | 1 | 50.00 | 1 | Not enough stock |
| 3 | 1 | 0.00 | 0 | Not enough stock |
+--------+-----------+--------+----------+------------------+

Have a look at the below query , it may help you
update item set note = case when precedingSum> t.QuantityAvailable then 'Not Enough Stock' Else '' End
from
(
select item.*,Product.QuantityAvailable,sum(Quantity) over(partition by item.ProductId order by item.LineId rows UNBounded Preceding)precedingSum
from Item inner join Product on item.ProductId=Product.ProductId
) t where t.LineId = Item.LineId

Related

Conditionally sum up the values of a column to a defined value [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 months ago.
Improve this question
I have a table like this:
id | name | amount (in $)
--------------
1 | A | 10
1 | A | 5
1 | A | 20
1 | A | 20
1 | A | 40
1 | A | 30
2 | B | 25
2 | B | 20
2 | B | 30
2 | B | 30
How do I sum the amount column of each Id above $5 so that when the sum reaches a certain value, say $50, it performs another sum for that id in the next row?
So, from the table above, we'll have:
id | name | amount (in $)
--------------
1 | A | 5 --skips the amount that is not above $5
1 | A | 50 --the next three rows sum up to $50
1 | A | 70 --the value of the next row is not up to $50, so it sums the next line. Summation is more than $50, but no problem
2 | B | 75
2 | B | 30
This may not be the simplest solution, but it works.
Your sample data is fundamentally flawed, because you need a column to order the rows by to accomplish what you want. I have have assumed you have such a column by adding an identify column to the sample data.
Points to help understanding:
Treat the rows of 5 or less separately; so identify the row so we can display it later, and filter it out from the running totals.
Calculate a running total across an id ignoring amounts which are too small.
With this running total work out when the specified threshold is crossed (by dividing by the threshold)
Flag to keep every row where the threshold value changes i.e. its been crossed once, twice, three times etc.
For each row kept, subtract the previous value to give the difference.
declare #MyTable table (id int, [name] char(1), amount money, uniqueid int identity (1,1));
insert into #MyTable (id, [name], amount)
values
(1,'A',10),
(1,'A',5),
(1,'A',20),
(1,'A',20),
(1,'A',40),
(1,'A',30),
(2,'B',25),
(2,'B',20),
(2,'B',30),
(2,'B',30);
declare #LowerAmount money = 5, #CutoffAmount money = 50;
with cte1 as (
select *
, sum(case when amount > #LowerAmount then amount else 0 end) over (partition by id order by uniqueid asc) RunningTotal
, round(sum(case when amount > #LowerAmount then amount else 0 end) over (partition by id order by uniqueid asc) / #CutoffAmount, 0, 1) CutoffTest
, case when amount <= #LowerAmount then 1 else 0 end TooSmall
from #MyTable
), cte2 as (
select *
, case when CutoffTest <> lag(CutoffTest, 1, 0) over (partition by id order by uniqueid asc) then RunningTotal else null end RowToKeep
from cte1
)
select id, [name]
, case when TooSmall = 1 then amount else RowToKeep-coalesce(lag(RowToKeep,1,0) over (partition by id order by uniqueid asc),0) end amount
from cte2
where TooSmall = 1 or RowToKeep is not null
order by uniqueid asc;
Returns as requested:
id
name
amount
1
A
5.00
1
A
50.00
1
A
70.00
2
B
75.00
2
B
30.00
Note: Providing DDL+DML (as I have shown here) makes it much easier to answer.

Calculate future inventory based an sales and production in SQL

I have 4 Tables: Storage, Sales, Prodcution, Production-cost
Storage example
Day
ProductID
Amount
2022-03-27
1
900
2022-03-27
2
1200
2022-03-28
1
950
2022-03-28
2
1200
Sales example
Date
ProductID
Amount
2022-04-2
1
50
2022-04-15
1
20
Production example
Date
ProductID
Amount
2022-04-1
1
70
2022-04-20
1
10
Production-Cost example
ProductID
1
2
glue
1
0
1
1
2
0
0
1
Production cost describes if and how much of a certain product you need to produce something. In this example you need 1 product 2 and 1 glue to produce product1.
I want to calculate my future inventory based on the future sales and production in SQL. I had this working with some golang code, but would prefer if the SQL query did it alone.
I tried different joins but i could not figure out how to subtract the values correctly and form new rows.
Here we get the most recent stock figures from storage, sum up the quantites produced and sold since (ignoring previous lines) and calculate the quantity in stock today.
I have included the table Production_cost in the join but have not used it. Should all product 2's be converted into 1's?
create table Products(
id int primary key);
insert into Products values
(1),
(2);
create table storage(
Day date,
ProductID int ,
Amount int,
foreign key fk_storage_productID(ProductID) references Products(id));
insert into storage values
('2022-03-27', 1,900),
('2022-03-27', 2,1200),
('2022-03-28', 1,950),
('2022-03-28', 2,1200);
create table Sales (
Day Date,
ProductID int,
Amount int,
foreign key fk_sales_productID(ProductID) references Products(id));
insert into Sales values
('2022-04-02',1,50),
('2022-04-15',1,20);
create table Production(
Day Date,
ProductID int,
Amount int,
foreign key fk_production_productID(ProductID) references Products(id));
insert into Production values
('2022-04-1', 1,70),
('2022-04-20', 1,10);
create table Production_Cost(
ProductID int,
p1 int,
p2 int,
glue int,
foreign key fk_production_cost_productID(ProductID) references Products(id));
insert into Production_Cost values
(1, 0, 1, 1),
(2, 0, 0, 1);
select
p.id as product,
st.Amount as latest_count,
coalesce(sum(sa.Amount),0) as sold,
coalesce(sum(pr.Amount),0) as produced,
st.Amount -
coalesce(sum(sa.Amount),0) +
coalesce(sum(pr.Amount),0) as calculated_stock
from Products p
left join (
select ProductID, Day, amount,
rank() over (partition by ProductID order by Day desc) rn
from storage )st on p.id = st.productID
left join Sales sa on p.id = sa.productID
left join Production pr on p.id = pr.productID
left join Production_Cost pc on p.id = pc.productID
where st.rn = 1
and (sa.Day > st.Day or sa.Day is null or st.Day is null)
and (pr.Day > st.Day or pr.Day is null or st.Day is null)
group by
p.id,
st.Amount
product | latest_count | sold | produced | calculated_stock
------: | -----------: | ---: | -------: | ---------------:
1 | 950 | 140 | 160 | 970
2 | 1200 | 0 | 0 | 1200
db<>fiddle here

How to create BigQuery this query in retail dataset

I have a table with user retail transactions. It includes sales and cancels. If Qty is positive - it sells, if negative - cancels. I want to attach cancels to the most appropriate sell. So, I have tables likes that:
| CustomerId | StockId | Qty | Date |
|--------------+-----------+-------+------------|
| 1 | 100 | 50 | 2020-01-01 |
| 1 | 100 | -10 | 2020-01-10 |
| 1 | 100 | 60 | 2020-02-10 |
| 1 | 100 | -20 | 2020-02-10 |
| 1 | 100 | 200 | 2020-03-01 |
| 1 | 100 | 10 | 2020-03-05 |
| 1 | 100 | -90 | 2020-03-10 |
User with ID 1 has the following actions: buy 50 -> return 10 -> buy 60 -> return 20 -> buy 200 -> buy 10 - return 90. For each cancel row (with negative Qty) I find the previous row (by Date) with positive Qty and greater than cancel Qty.
So I need to create BigQuery queries to create table likes this:
| CustomerId | StockId | Qty | Date | CancelQty |
|--------------+-----------+-------+------------+-------------|
| 1 | 100 | 50 | 2020-01-01 | -10 |
| 1 | 100 | 60 | 2020-02-10 | -20 |
| 1 | 100 | 200 | 2020-03-01 | -90 |
| 1 | 100 | 10 | 2020-03-05 | 0 |
Does anybody help me with these queries? I have created one candidate query (split cancel and sales, join them, and do some staff for removing), but it works incorrectly in the above case.
I use BigQuery, so any BQ SQL features could be applied.
Any ideas will be helpful.
You can use the following query.
;WITH result AS (
select t1.*,t2.Qty as cQty,t2.Date as Date_t2 from
(select *,ROW_NUMBER() OVER (ORDER BY qty DESC) AS [ROW NUMBER] from Test) t1
join
(select *,ROW_NUMBER() OVER (ORDER BY qty) AS [ROW NUMBER] from Test) t2
on t1.[ROW NUMBER] = t2.[ROW NUMBER]
)
select CustomerId,StockId,Qty,Date,ISNULL(cQty, 0) As CancelQty,Date_t2
from (select CustomerId,StockId,Qty,Date,case
when cQty < 0 then cQty
else NULL
end AS cQty,
case
when cQty < 0 then Date_t2
else NULL
end AS Date_t2 from result) t
where qty > 0
order by cQty desc
result: https://dbfiddle.uk
You can do this as a gaps-and-islands problem. Basically, add a grouping column to the rows based on a cumulative reverse count of negative values. Then within each group, choose the first row where the sum is positive. So:
select t.* (except cancelqty, grp),
(case when min(case when cancelqty + qty >= 0 then date end) over (partition by customerid grp) = date
then cancelqty
else 0
end) as cancelqty
from (select t.*,
min(cancelqty) over (partition by customerid, grp) as cancelqty
from (select t.*,
countif(qty < 0) over (partition by customerid order by date desc) as grp
from transactions t
) t
from t
) t;
Note: This works for the data you have provided. However, there may be complicated scenarios where this does not work. In fact, I don't think there is a simple optimal solution assuming that the returns are not connected to the original sales. I would suggest that you fix the data model so you record where the returns come from.
The below query seems to satisfy the conditions and the output mentioned.The solution is based on mapping the base table (t) and having the corresponding canceled qty row alongside from same table(t1)
First, a self join based on the customer and StockId is done since they need to correspond to the same customer and product.
Additionally, we are bringing in the canceled transactions t1 that happened after the base row in table t t.Dt<=t1.Dt and to ensure this is a negative qty t1.Qty<0 clause is added
Further we cannot attribute the canceled qty if they are less than the Original Qty. Therefore I am checking if the positive is greater than the canceled qty. This is done by adding a '-' sign to the cancel qty so that they can be compared easily. -(t1.Qty)<=t.Qty
After the Join, we are interested only in the positive qty, so adding a where clause to filter the other rows from the base table t with canceled quantities t.Qty>0.
Now we have the table joined to every other canceled qty row which is less than the transaction date. For example, the Qty 50 can have all the canceled qty mapped to it but we are interested only in the immediate one came after. So we first group all the base quantity values and then choose the date of the canceled Qty that came in first in the Having clause condition HAVING IFNULL(t1.dt, '0')=MIN(IFNULL(t1.dt, '0'))
Finally we get the rows we need and we can exclude the last column if required using an outer select query
SELECT t.CustomerId,t.StockId,t.Qty,t.Dt,IFNULL(t1.Qty, 0) CancelQty
,t1.dt dt_t1
FROM tbl t
LEFT JOIN tbl t1 ON t.CustomerId=t1.CustomerId AND
t.StockId=t1.StockId
AND t.Dt<=t1.Dt AND t1.Qty<0 AND -(t1.Qty)<=t.Qty
WHERE t.Qty>0
GROUP BY 1,2,3,4
HAVING IFNULL(t1.dt, '0')=MIN(IFNULL(t1.dt, '0'))
ORDER BY 1,2,4,3
fiddle
Consider below approach
with sales as (
select * from `project.dataset.table` where Qty > 0
), cancels as (
select * from `project.dataset.table` where Qty < 0
)
select any_value(s).*,
ifnull(array_agg(c.Qty order by c.Date limit 1)[offset(0)], 0) as CancelQty
from sales s
left join cancels c
on s.CustomerId = c.CustomerId
and s.StockId = c.StockId
and s.Date <= c.Date
and s.Qty > abs(c.Qty)
group by format('%t', s)
if applied to sample data in your question - output is

SQL Server map payments to products

We have shopping carts that might have included products and payments.
Since these payments will be made to the carts, there will be no relation between the products and the payments except that they are in the same cart.
There are cases that these products will be invoiced individually even though they are in the same cart.
To create the invoices for the products we need the payment details, so we have to map the products to the payments.
These are our tables:
create table Products
(
ItemId int primary key,
CartId int not null,
ItemAmount smallmoney not null
)
create table Payments
(
PaymentId int primary key,
CartId int not null,
PaymentAmount smallmoney not null
)
create table MappedTable
(
ItemId int not null,
PaymentId int not null,
Amount smallmoney not null
)
INSERT INTO Products (ItemId, CartId, ItemAmount)
VALUES (1, 1, 143.49), (2, 1, 143.49), (3, 1, 143.49), (4, 2, 50.00), (5, 3, 75.00), (6, 3, 75.00)
INSERT INTO Payments (PaymentId, CartId, PaymentAmount)
VALUES (1, 1, 376.47), (2, 1, 54.00), (3, 2, 60.00), (4, 3, 140.00)
--select * from Products
--select * from Payments
--DROP TABLE Products
--DROP TABLE Payments
--DROP TABLE MappedTable
Products
ItemId | CartId | ItemAmount
------ | ------ | ----------
1 | 1 | 143.49
2 | 1 | 143.49
3 | 1 | 143.49
4 | 2 | 50.00
5 | 3 | 75.00
6 | 3 | 75.00
Payments
PaymentId | CartId | PaymentAmount
--------- | ------ | -------------
1 | 1 | 376.47
2 | 1 | 54.00
3 | 2 | 60.00
4 | 3 | 140.00
The order of the products and the payments may differ.
We need the output to look like this:
MappingTable
ItemId | PaymentId | MappedAmount
------ | --------- | ------------
1 | 1 | 143.49
2 | 1 | 143.49
3 | 1 | 89.49
3 | 2 | 54.00
4 | 3 | 50.00 (Remaining 10.00 from Payment 3 will be ignored)
5 | 4 | 75.00
6 | 4 | 65.00 (Missing 10.00 from Payment 4 will be ignored)
Cart 1: Sum of payments = sum of product costs
Cart 2: Sum of payments > sum of product costs. Only take the total product cost. Ignore the remaining 10.00
Cart 3: Sum of payments < sum of product costs. Take all the payments, ignore the fact that the payment is 10.00 short.
I thought that a query like the one below may solve the problem, but no luck.
insert into MappedTable
select
prd.ItemId, pay.PaymentId,
(Case
when prd.ItemAmount - isnull((select sum(m.Amount)
from MappedTable m
where m.ItemId = prd.ItemId), 0) <= pay.PaymentAmount - isnull((select sum(m.Amount) from MappedTable m where m.PaymentId = pay.PaymentId), 0)
then prd.ItemAmount - isnull((select sum(m.Amount) from MappedTable m where m.ItemId = prd.ItemId), 0)
else pay.PaymentAmount - isnull((select sum(m.Amount) from MappedTable m where m.PaymentId = pay.PaymentId), 0)
end)
from
Products prd
inner join
Payments pay on pay.CartId = prd.CartId
where
prd.ItemAmount > isnull((select sum(m.Amount) from MappedTable m where m.ItemId = prd.ItemId), 0)
and pay.PaymentAmount > isnull((select sum(m.Amount) from MappedTable m where m.PaymentId = pay.PaymentId), 0)
I've read about CTE (Common Table Expressions) and set-based approaches but I couldn't handle the issue.
So is this possible without using a cursor or a while loop?
Generally, this kind of task is referred to as a "knapsack problem", which is known to have no solution more efficient than brute forcing all possible combinations. In your case, however, you have additional conditions, namely ordered sets of both items and payments, so it is actually solvable using "overlapping intervals" technique.
The idea is to generate ranges of items and payments (1 pair of ranges per cart) and then look which payments overlap with which items, sequentially.
For any item-payment combination, there are 3 possible scenarios:
Payment covers the beginning of the item range (possibly completely covering the item);
Payment is completely inside the item;
Payment covers the end of item, thus "closing" it.
So, all that is needed is, for every item, find all suitable payments that match the aforementioned criteria, and order them by their identifiers. Here is a query that does it:
with cte as (
-- Project payment ranges, per cart
select pm.*, sum(pm.PaymentAmount) over(partition by pm.CartId order by pm.PaymentId) as [RT]
from #Payments pm
)
select q.ItemId, q.PaymentId,
-- Calculating the amount from payment that goes for this item
case q.Match
when 1 then q.PaymentRT - (q.ItemRT - q.ItemAmount)
when 2 then q.PaymentAmount
when 3 then case
-- Single payment spans over several items
when q.PaymentRT >= q.ItemRT and q.PaymentRT - q.PaymentAmount <= q.ItemRT - q.ItemAmount then q.ItemAmount
-- Payment is smaller than item
else q.ItemRT - (q.PaymentRT - q.PaymentAmount)
end
end as [Amount]
--, q.*
from (
select
sq.ItemId, pm.PaymentId, sq.ItemAmount, sq.RT as [ItemRT],
pm.PaymentAmount, pm.RT as [PaymentRT],
row_number() over(partition by sq.CartId, sq.ItemId, pm.PaymentId order by pm.RT) as [RN],
pm.Match
--, sq.CartId
from (
select pr.*, sum(pr.ItemAmount) over(partition by pr.CartId order by pr.ItemId) as [RT]
from #Products pr
) sq
outer apply (
-- First payment to partially cover this item
select top (1) c.*, 1 as [Match] from cte c where c.CartId = sq.CartId
and c.RT > sq.RT - sq.ItemAmount and c.RT < sq.RT
order by sq.RT
union all
-- Any payments that cover this item only
select c.*, 2 as [Match] from cte c where c.CartId = sq.CartId
and c.RT - c.PaymentAmount > sq.RT - sq.ItemAmount
and c.RT < sq.RT
union all
-- Last payment that covers this item
select top (1) c.*, 3 as [Match] from cte c where c.CartId = sq.CartId
and c.RT >= sq.RT
order by sq.RT
) pm
) q
where q.RN = 1;
The outer apply section is where I get payments related to each item. The only problem is, if a payment covers an item in its entirety, it will be listed several times. In order to remove these duplicates, I have ordered matches using row_number() and added an additional wrapping level - subquery with the q alias - where I cut off any duplicated rows by filtering the row number value.
P.S. If your SQL Server version is prior to 2012, you will need to calculate running totals using one of many approaches available on the Internet, because sum() over(order by ...) is only available on 2012 and later versions.

Query to differentiate between stock and in saleorder

I have two tables. Table A contains one column Priority. Table B contains Priority, Lot and salesorder.
Table A
Priority
--------
122
123
124
Table B
Priority | Lotid | salesorderline
--------------------------------
122 | 14257 | 4
122 | 14528 | 6
122 | 14782 | 4
122 | 14587 | 0
I'm expecting results like:
Priority | TotalLot | salesorder | In Stock
-------------------------------------------
122 | 4 | 3 | 1
If salesorderline is greater than 0 than its a salesorder otherwise stock
So for each Priority in Table A (which I'll call Priorities) you want aggregate data on each row group in Table B (Lots)?
There are multiple ways to build this query. The simplest is a single query with predicated aggregate functions:
SELECT
Lots.Priority,
COUNT(*) AS TotalLots,
COUNT(CASE WHEN SalesOrderLine > 0 THEN 1 ELSE NULL END) AS SalesOrder,
COUNT(CASE WHEN SalesOrderLine <= 0 THEN 1 ELSE NULL END) AS InStock
FROM
Lots
INNER JOIN Priorities ON Priorities.Priority = Lots.Priority
-- this JOIN doesn't do anything because the Priorities table does not contain any useful data at this point
GROUP BY
Priority
ORDER BY
Priority ASC
Note that I feel your database design is not correct - I don't see why row SalesOrder/Lot row should represent how something is in stock or not, and overloading the SalesOrderLine to give it meaning is a bad design.