Как реализовать FIFO в sql
Я работаю над реализацией FIFO в sql.
У меня есть концепция номера партии в моей заявке.
Если предположим, что я продаю на складе, то мое заявление должно сказать мне, какой инвентарь является первым.
Давайте. Скажем, я купил инвентарь " а " 4-го августа, 5-го августа и 6-го августа
On 4th Aug - A Inventory has batch number BT002 - 10 (Qty)
On 5th Aug - A's Inventory has batch number BT003 - 15 (Qty)
On 6th Aug - A's Inventory has batch number BT001 - 10 (Qty)
Итак, теперь у меня в руках есть акции в следующем виде:
A Inventory
BT002 - 10 - 4-Aug
BT003 - 15 - 5-Aug
BT001 - 10 - 6-Aug
Теперь, если я хочу продать этот инвентарь кому-либо, то мое заявление должно сказать мне, что я должен продать
BT002 (номер партии) инвентаризация первая, потому что она пришла первой.
Это была концепция, которую я использую в своем приложении.
Теперь я хочу продать 15 кол-во Из " А " (инвентаря).
Тогда O/p должно быть таким:
BT002 - 10
BT003 - 5
Вот мой запрос:
SELECT ISNULL(SUM(qty),0) AS Qty,batch_no,accept_date FROM RS_GIN_Master
GROUP BY batch_no,accept_date
HAVING ISNULL(SUM(qty),0) <= 15
ORDER BY accept_date asc
O / p данного запроса:

Как я могу получить O/P вот так:
BT002 - 10
BT003 - 5
Любая помощь будет оценена по достоинству.
Заранее спасибо.
4 ответов:
Это должно сработать для вас:
рабочий образец на скрипкеCREATE FUNCTION [dbo].[GetBatchAmounts] ( @requestedAmount int ) RETURNS @tBatchResults TABLE ( Batch nvarchar(50), Amount int ) AS BEGIN /*This is just a mock of ersults of your query*/ DECLARE @RS_GIN_Master TABLE( Qty int, batch_no NVARCHAR(max), accept_date DATETIME ) insert into @RS_GIN_Master(Qty,batch_no,accept_date) SELECT 10,'BT002', CAST(CAST(2014 AS varchar) + '-' + CAST(8 AS varchar) + '-' + CAST(4 AS varchar) AS DATETIME) insert into @RS_GIN_Master(Qty,batch_no,accept_date) SELECT 10,'BT003', CAST(CAST(2014 AS varchar) + '-' + CAST(8 AS varchar) + '-' + CAST(5 AS varchar) AS DATETIME) insert into @RS_GIN_Master(Qty,batch_no,accept_date) SELECT 10,'BT001', CAST(CAST(2014 AS varchar) + '-' + CAST(8 AS varchar) + '-' + CAST(6 AS varchar) AS DATETIME) /*---------------------------*/ DECLARE @Qty int DECLARE @batch_no NVARCHAR(max) DECLARE @accept_date DATETIME DECLARE myCursor CURSOR FOR SELECT Qty, batch_no, accept_date FROM @RS_GIN_Master ORDER BY accept_date ASC OPEN myCursor FETCH NEXT FROM myCursor INTO @Qty, @batch_no,@accept_date WHILE (@@FETCH_STATUS = 0 AND @requestedAmount > 0 ) BEGIN Declare @actualQty int IF @requestedAmount > @Qty SET @actualQty = @Qty ELSE SET @actualQty = @requestedAmount INSERT INTO @tBatchResults (batch, Amount) SELECT @batch_no, @actualQty set @requestedAmount = @requestedAmount - @actualQty FETCH NEXT FROM myCursor INTO @Qty, @batch_no,@accept_date END /*WHILE*/ CLOSE myCursor DEALLOCATE myCursor RETURN ENDПросто убедитесь, что вы заменили отмеченную часть функции вашим запросом...
Вам нужно создать хранимую процедуру в базе данных и взять количество из таблицы запасов. И вы также должны иметь идентификатор каждой записи, чтобы обновить эти записи, откуда вы взяли это количество.
Alter PROCEDURE sp_UpdateStockForSale @batchNO varchar(10), @qty decimal(9,3) AS BEGIN Create Table #tmpOutput(ID int identity(1,1), StockID int, batchNo varchar(10), qty decimal(9,3)); SET NOCOUNT ON; DECLARE @ID int; DECLARE @Stock Decimal(9,3); DECLARE @TEMPID int; Select @TEMPID=(Max(ID)+1) From RS_GIN_Master Where qty > 0 And batch_no = @batchNO; While (@qty > 0) BEGIN Select @ID=ID, @Stock=qty From RS_GIN_Master Where qty > 0 And batch_no = @batchNO AND ID < @TEMPID Order By accept_date Desc; --If Outward Qty is more than Stock IF (@Stock < @qty) BEGIN SET @qty = @qty - @Stock; SET @Stock = 0; END --If Outward Qty is less than Stock ELSE BEGIN SET @Stock = @Stock - @qty; SET @qty = 0; END Insert Into #tmpOutput(StockID,batchNo,qty)Values(@ID,@batchNO,@Stock); SET @TEMPID = @ID; --This will update that record don't need it now. --Update RS_GIN_Master Set qty = @Stock Where ID=@ID END Select StockID, batchNo, qty From #tmpOutput; END GOПриведенный выше пример не компилируется, но вы можете получить логику, как вы можете получить записи из таблицы запасов в соответствии с методом FIFO. Вы можете использовать
accept_dateвместоIDв таблице RS_GIN_Master. но, я бы предпочел сделать его уникальным, так что, если я хочу получить конкретная запись тогда может быть возможна.
Один запрос .. вот так
Это должно быть настроено для вас, так как у вас есть группы и другие вещи, только для примера целей.
;with qty as ( select 15 as value ) ,l as ( select ROW_NUMBER () over (order by accept_date desc) rn ,* from xxx ) ,q as ( select batch_no ,accept_date ,case when value>qty then value-qty else 0 end as remainder ,case when value>qty then qty else value end as used ,rn from l cross join qty where rn=1 union all select r.batch_no ,r.accept_date ,case when q.remainder>r.qty then q.remainder-r.qty else 0 end as remainder ,case when q.remainder>r.qty then r.qty else q.remainder end as used ,r.rn from q join l r on q.rn+1 = r.rn where q.remainder!=0 ) select * from q where used != 0И фиффл для него http://sqlfiddle.com/#! 6 / 9b063/34/0
Ниже должно работать для вас
Create table RS_GIN_Master (id int, qty int, batch_no varchar(5), accept_date Datetime ) GO Insert into RS_GIN_Master (id, qty, batch_no, accept_date) values(1,10,'BT001','2018-04-06') Insert into RS_GIN_Master (id, qty, batch_no, accept_date) values(2,10,'BT002','2018-04-04') Insert into RS_GIN_Master (id, qty, batch_no, accept_date) values(3,15,'BT003','2018-05-06') GO ---------------------------- CREATE PROC FIFO @TakenQty int AS BEGIN WITH cte AS (SELECT *, SUM(qty) OVER (ORDER BY accept_date, id ASC) as CumQty FROM RS_GIN_Master WHERE qty>0) SELECT TOP ((SELECT COUNT(*) FROM cte WHERE CumQty <@TakenQty)+1) batch_no, accept_date, CASE WHEN CumQty<@TakenQty THEN qty ELSE @TakenQty -(CumQty-Qty) END AS TakenOut FROM cte ENDРезультат
| batch_no | accept_date | TakenOut | |----------|----------------------|----------| | BT002 | 2018-04-04T00:00:00Z | 10 | | BT001 | 2018-04-06T00:00:00Z | 5 |
Comments