Increase the performance of an inventory (FIFO) query - sql

My goal is to get the price from item which goes into stock and put the price into out item by (FIFO order by TranDate), then calculate the total price of any line of production (" lineid ").
This is what I have done
-- temp table for result
declare #Test table ( stockID int , OriQty decimal(16,2) ,inuse decimal(16,2) , price decimal(16,2) , lineid int , Inid int )
declare #StockIn table (ID int , StockID int ,qty decimal(16,2),Price decimal(16,2), tranDate Date , running int)
insert into #StockIn(ID , StockID , qty , Price , tranDate , running) values
(1,1 , 15 , 430 , '2014-10-09' , 1),
(2,1 , 10 , 431, '2014-12-09' , 2),
(3,1 , 15 , 432, '2015-02-02' , 3),
(4,2 , 15 , 450, '2014-08-05' , 1),
(5,2 , 6 , 450, '2014-10-09' , 2),
(6,2 , 15 , 452, '2015-02-02' , 3)
-- lineid = line production
declare #StockOut table (ID int , StockID int ,qty decimal(16,2), lineid int, tranDate Date)
insert into #StockOut(ID , StockID ,qty , lineid, tranDate )
values
(1,1 , 20 , 2, '2014-10-10'),
(2,1 , 10 , 4, '2014-12-20'),
(3,2 , 12 , 8, '2014-10-01'),
(4,2 , 3 , 8, '2014-10-01') ;
DECLARE #intFlag INT
SET #intFlag = 1 -- initial of loop
WHILE (#intFlag <= (Select Max(ID) from #StockOut) )
BEGIN
declare #stockID int
declare #ids table (ID int , Inuse decimal(16,2))
declare #lineid int
declare #qtyToRemove decimal(16,2) -- get qty from #StockOut
--get data from #StockOut row by row
select #stockID = StockID , #qtyToRemove = qty , #lineid = lineid from #StockOut where ID = #intFlag;
with cte as (
select *, sum(qty) over (order by tranDate ASC , qty DESC , tranDate ASC Rows UNBOUNDED PRECEDING) - #qtyToRemove
as Total FROM #StockIn Where stockID = #stockID )
-- running FIFO from #StockIn and update QTy when stock is running out
, RunningFIFO as (
select cte.StockID , cte.qty AS OriginalQty , Case when
case when 0 > total then cte.qty else cte.qty-total End > 0 then case when 0 > total then cte.qty else cte.qty-total End else 0 End As Inuse
, cte.Price , #lineid AS lineid , id
from cte
)
-- insert result into result table
insert into #test (stockID , OriQty ,inuse , cte.Price , lineid ,Inid ) OUTPUT inserted.Inid , inserted.inuse into #ids select * from RunningFIFO Where Inuse > 0
UPDATE #StockIn set qty = qty - inuse from #ids A inner join #StockIn B on A.ID = b.ID
SET #intFlag = #intFlag + 1
END
Select sum(inuse * price) AS total , lineid from #Test group by lineid
But when data are more than a thousand, this query runs super slow.
How could I increase the performance of this query?

Related

Update Temp Table

I need to update temp table in sql 2014 but this code seems wrong .
first i select all invoices and its Qty from invoices and set Inventory Qty with 0. and second statement i need to update each line by qty of inventory to compare later and use this code.declare #DifferenceTable table (
DataAreaId nvarchar(10) ,
SalesId nvarchar(50) ,
InvoiceId nvarchar(50) ,
ItemId nvarchar(50),
InvoiceQty decimal(16,4) ,
InventoryQty decimal(16,4)
)
insert into #DifferenceTable (DataAreaId , SalesId , InvoiceId , ItemId , InvoiceQty , InventoryQty )
select CustInvoiceTrans.DATAAREAID , CustInvoiceTrans.SALESID , CustInvoiceTrans.INVOICEID , CustInvoiceTrans.ITEMID , sum(CustInvoiceTrans.QTY) , 0. as InventoryQty
from CustInvoiceTrans with(nolock)
group by CustInvoiceTrans.DATAAREAID , CustInvoiceTrans.SALESID , CustInvoiceTrans.INVOICEID , CustInvoiceTrans.ITEMID
update #DifferenceTable
set InventoryQty = tt.Qty from
(select sum(InventTrans.QTY)*-1 as Qty , InventTransOrigin.DATAAREAID , REFERENCEID , InventTrans.INVOICEID , InventTrans.ITEMID
from InventTransOrigin
left join InventTrans on InventTrans.INVENTTRANSORIGIN = InventTransOrigin.RECID
and InventTrans.DATAAREAID = InventTransOrigin.DATAAREAID
and InventTrans.ITEMID = InventTransOrigin.ITEMID
where REFERENCECATEGORY = 0
group by InventTransOrigin.DATAAREAID , REFERENCEID , InventTrans.INVOICEID , InventTrans.ITEMID
) tt
where #DifferenceTable.DataAreaId = tt.DATAAREAID and #DifferenceTable.SalesId = tt.REFERENCEID
and tt.INVOICEID = #DifferenceTable.InvoiceId and tt.ITEMID = #DifferenceTable.ItemId
select * from #DifferenceTable`

Insert into temp table from stored procedure causes error

I have this stored procedure:
ALTER Procedure [dbo].[sp_Prd_Dashboard_Summary]
(#Period AS INT)
AS
SELECT
SiteName AS SiteName,
MAX(Country) AS Country,
BudgetPrj,
MAX(PeriodEnd) AS PeriodEnd,
MAX(DaysMtd) AS DaysMtd,
MAX(ToGoMtd) AS ToGoMtd,
MAX(PeriodToTDays) AS PeriodToTDays,
SUM(MTDRevenue) AS MtdRev,
SUM(MTDRevenue) / NULLIF(MAX(DaysMTD), 0) * MAX(PeriodToTDays) AS PrjRevenue,
SUM(BdgRevenue) AS BdgRev, SUM(TrgRevenue) AS TrgRev,
SUM(BCMMtd) AS BCMMtd, SUM(HrsMtd) AS HrsMTD,
SUM(FuelVal) AS FuelVal, SUM(FuelLtrs) AS FuelLtrs,
SUM(FuelVal) / NULLIF(SUM(MTDRevenue), 0) AS FuelPerc
FROM
(SELECT
St.SiteName as SiteName,
St.Country as Country,
Null as BudgetPrj, Prd.PeriodEnd as PeriodEnd,
Day(GetDate()) as DaysMtd,
Prd.PeriodNoDays - Day(GetDate()) as ToGoMtd,
Prd.PeriodNoDays as PeriodToTDays,
0 as MTDRevenue, 0 as BdgRevenue,
0 as TrgRevenue, 0 as BCMMtd,
0 as HrsMtd, 0 as FuelVal,
0 as FuelLtrs
FROM
Periods Prd
JOIN
Sites St ON Prd.PeriodSiteID = St.SiteId
WHERE
Prd.Period = #Period AND St.SiteActive = 1
UNION All
Select SiteName as SiteName
, Dit.Country as Country
, Null as BudgetPrj
, Null as PeriodEnd
, 0 DaysMtd
, 0 as ToGoMtd
, 0 as PeriodToTDays
, IIF(Dit.Wcode = 101,
IIF(DiT.WBillMeth = 'Hours', DiT.Hrs * DiT.OpBill,
IIF(DiT.WBillMeth = 'BCM', Loads * DiT.ModelSize * DiT.WBillRate,
IIF(DiT.WBillMeth = 'Cost Plus', (DiT.Hrs * (DiT.OwnBill + DiT.OpBill)) +
(DiT.ShiftHrs * DiT.EmpBill),0))),0) as MTDRevenue
, 0 as BdgRevenue
, 0 as TrgRevenue
, IIF(DiT.WBillMeth = 'BCM', Loads * DiT.ModelSize, 0) as BCMMtd
, IIF(Dit.Wcode = 101,
IIF(DiT.WBillMeth <> 'BCM', DiT.Hrs, 0),0) as HrsMtd
, DiT.Fuel * DiT.FuelRate as FuelVal
, DiT.Fuel as FuelLtrs
From DataInputTotal DiT
Where DiT.Period = #Period and DiT.SiteActive = 1
Union All
Select SiteName as SiteName
, St.Country as Country
, Bdgt.BudgetProject as BudgetPrj
, Prd.PeriodEnd as PeriodEnd
, 0 as DaysMtd
, 0 as ToGoMtd
, 0 as PeriodToTDays
, 0 as MTDRevenue
, PrjRev as BdgRevenue
, BudgTarget as TrgRevenue
, 0 as BCMMtd
, 0 as HrsMtd
, 0 as FuelVal
, 0 as FuelLtrs
From Budget Bdgt Join
Sites St on Bdgt.SiteId = St.SiteId Join
Periods Prd on Bdgt.Period = prd.Period and Bdgt.SiteId = Prd.PeriodSiteID
Where Bdgt.Period = #Period and St.SiteActive = 1
) a
Group By SiteName, BudgetPrj
I am trying to call the procedure and insert the result into a temp table with the below script:
Declare #Period int = 22
Declare #DaysinMonth Int = 29
Declare #DayHrs Int = 24
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL DROP TABLE #Temp
Create Table #Temp (SiteName nvarchar(50)
, Country nvarchar(50)
, BudgetPrj nvarchar(50)
, PeriodEnd DateTime
, DaysMtd Int
, ToGoMtd Int
, PeriodToTDays Int
, MtdRev Numeric(13,2)
, PrjRevenue Numeric(13,2)
, BdgRev Numeric(13,2)
, TrgRev Numeric(13,2)
, BCMMtd Numeric(13,2)
, HrsMtd Numeric(13,2)
, FuelVal Numeric(13,2)
, FuelLtrs Numeric(13,2)
, FuelPerc Numeric(13,2)
, FltCnt Int
, Availibility Numeric(13,2)
, Utilization Numeric(13,2)
, Idle Numeric(13,2)
)
Insert #temp
Exec sp_Prd_Dashboard_Summary #Period
Insert into #temp
Exec summary_fleet_performance #DayHrs, #Period, #DaysinMonth
When running the script I get the following error:
Column name or number of supplied values does not match table definition.
I have checked the aliases of the SELECT and all columns have names.
I ended creating two temp tables and inserting each stored procedure into each table and then joining them.
It worked perfectly for me:
ALTER Procedure [dbo].[summary_dashboard]
(
#Period int,
#DaysinMonth Int,
#DayHrs Int
)
as
Declare #Tbl1 as table (SiteName nvarchar(50) null
, Country nvarchar(50) null
, BudgetPrj nvarchar(50) null
, PeriodEnd DateTime null
, DaysMtd Int null
, ToGoMtd Int null
, PeriodToTDays Int null
, MtdRev Numeric(13,2) null
, PrjRevenue Numeric(13,2) null
, BdgRev Numeric(13,2) null
, TrgRev Numeric(13,2) null
, BCMMtd Numeric(13,2) null
, HrsMtd Numeric(13,2) null
, FuelVal Numeric(13,2) null
, FuelLtrs Numeric(13,2) null
, FuelPerc Numeric(13,2) null
)
Declare #Tbl2 as Table (SiteName nvarchar(50) null
, FltCnt Int null
, Availability Numeric (5,2) null
, Utilization Numeric (5,2) Null
, Idle Numeric(5,2)
)
insert into #Tbl1 (SiteName
, Country
, BudgetPrj
, PeriodEnd
, DaysMtd
, ToGoMtd
, PeriodToTDays
, MtdRev
, PrjRevenue
, BdgRev
, TrgRev
, BCMMtd
, HrsMtd
, FuelVal
, FuelLtrs
, FuelPerc
)
Exec sp_Prd_Dashboard_Summary #Period
insert into #tbl2 (SiteName
, FltCnt
, Availability
, Utilization
, Idle
)
Exec summary_fleet_performance #DayHrs, #Period, #DaysinMonth
select tbl1.SiteName
, tbl1.Country
, tbl1.BudgetPrj
, tbl1.PeriodEnd
, tbl1.DaysMtd
, tbl1.ToGoMtd
, tbl1.PeriodToTDays
, tbl1.MtdRev
, tbl1.PrjRevenue
, tbl1.BdgRev
, tbl1.TrgRev
, tbl1.BCMMtd
, tbl1.HrsMtd
, tbl1.FuelVal
, tbl1.FuelLtrs
, tbl1.FuelPerc
, tbl2.FltCnt
, tbl2.Availability
, tbl2.Utilization
, tbl2.Idle
from #tbl1 tbl1 full outer join
#tbl2 tbl2
on tbl1.SiteName = tbl2.SiteName
TRY THIS: Your stored procedure is returning 14 columns and temporary table has more than that so you have to mention columnS in the INSERT INTO #TEMP as below and if you are not specifying the columns name of table then returning columns from the STORED PROCEDURE also must be same.
INSERT INTO #temp(SiteName
, Country
, BudgetPrj
, PeriodEnd
, DaysMtd
, ToGoMtd
, PeriodToTDays
, MtdRev
, PrjRevenue
, BdgRev
, TrgRev
, BCMMtd
, HrsMtd
, FuelVal
, FuelLtrs)
Exec sp_Prd_Dashboard_Summary #Period
The temporary table to which you are trying to insert rows contains more columns than the result from stored procedure. Provide column names in insert query, like this:
Insert into table(Column1, Column2....)

Default to a value when a sub-query statement fails?

I have the following query:
INSERT INTO dbo.ResourceOrderCustomersOrders
( OrderId ,
Type ,
CustomerId ,
ResourceId ,
Quantity ,
Created ,
CreatedBy
)
VALUES ( ( SELECT MAX(OrderId) + 1
FROM dbo.ResourceOrderCustomersOrders
) , -- OrderId - int
'PENDING' , -- Type - varchar(50)
( SELECT MAX(CustomerId)
FROM dbo.ResourceOrderCustomers
WHERE UPPER(FirstName) = UPPER(#Firstname)
AND UPPER(Surname) = UPPER(#Surname)
AND UPPER(Email) = UPPER(#Email)
) , -- CustomerId - int
( SELECT MAX(ResourceId)
FROM dbo.ResourceOrderFormContent
WHERE DisplayTitle = #ResourceName
) , -- ResourceId - int
#ResourceQuantity ,
GETDATE() , -- Created - datetime
'WebsiteForm' -- CreatedBy - varchar(20)
);
In cases where a subquery fails I'd like to default to a value of my choosing (to hold unspecified records).
For example, were the following to fail to retrieve a result because a record doesn't exist:
SELECT MAX(ResourceId)
FROM dbo.ResourceOrderFormContent
WHERE DisplayTitle = #ResourceName
Then I would want to return the number '999' (unspecified record). What would be the best way to approach this?
I've tried to use try / catch but I'm being told this is invalid syntax. Here is my attempt:
INSERT INTO dbo.ResourceOrderCustomersOrders
( OrderId ,
Type ,
CustomerId ,
ResourceId ,
Quantity ,
Created ,
CreatedBy
)
VALUES ( ( SELECT MAX(OrderId) + 1
FROM dbo.ResourceOrderCustomersOrders
) , -- OrderId - int
'PENDING' , -- Type - varchar(50)
( SELECT MAX(CustomerId)
FROM dbo.ResourceOrderCustomers
WHERE UPPER(FirstName) = UPPER(#Firstname)
AND UPPER(Surname) = UPPER(#Surname)
AND UPPER(Email) = UPPER(#Email)
) , -- CustomerId - int
( BEGIN TRY
SELECT MAX(ResourceId)
FROM dbo.ResourceOrderFormContent
WHERE DisplayTitle = #ResourceName
END TRY
BEGIN CATCH
SELECT 999
END CATCH
) , -- ResourceId - int
#ResourceQuantity ,
GETDATE() , -- Created - datetime
'WebsiteForm' -- CreatedBy - varchar(20)
);
Max will always return NULL if no rows found. So You can use ISNULL.
SELECT ISNULL(MAX(ResourceId), 999)
FROM dbo.ResourceOrderFormContent
WHERE DisplayTitle = #ResourceName

Selection of records on bases of date

Below is my query and I want the selection of Qty from those SKU which is going to expire first. Please help me how can I do this.
DECLARE #Data table (Id int identity(1,1)
, SKU varchar(10)
, QtyRec int
, Expiry date
, Rec date)
DECLARE #Qty int = 20
INSERT #Data VALUES
('001A', 5 ,'2017-01-15','2015-11-14'),
('001A', 8 ,'2017-01-10','2015-11-14'),
('001A', 6 ,'2015-12-15','2015-11-15'),
('001A', 25,'2016-01-01','2015-11-16'),
('001A', 9 ,'2015-12-20','2015-11-17')
;WITH sumqty AS
(
SELECT *, SUM(QtyRec) OVER (PARTITION BY SKU ORDER BY Id) AS TotalQty FROM #Data
)
,takeqty AS (
SELECT *,
CASE
WHEN #Qty >= TotalQty THEN QtyRec
ELSE #Qty - ISNULL(LAG(TotalQty) OVER (PARTITION BY SKU ORDER BY Id), 0)
END AS TakeQty
FROM sumqty
)
SELECT * FROM takeqty WHERE TakeQty > 0
There are many possible outcomes depends on your question:
If you want to order result-set based on Expiry date ascending order, then Use ORDER BY Expiry at the end of CTEs query. Or select top expire: Use SELECT TOP(1) ROW_NUMBER() OVER(ORDER BY Expiry) AS 'SN' instead of SELECT ROW_NUMBER() OVER(ORDER BY Expiry) AS 'SN'
DECLARE #Data table (Id int identity(1,1)
, SKU varchar(10)
, QtyRec int
, Expiry date
, Rec date)
DECLARE #Qty int = 20
INSERT #Data VALUES
('001A', 5 ,'2017-01-15','2015-11-14'),
('001A', 8 ,'2017-01-10','2015-11-14'),
('001A', 6 ,'2015-12-15','2015-11-15'),
('001A', 25,'2016-01-01','2015-11-16'),
('001A', 9 ,'2015-12-20','2015-11-17');
WITH sumqty AS
(
SELECT *, SUM(QtyRec) OVER (PARTITION BY SKU ORDER BY Id) AS TotalQty FROM #Data
)
,takeqty AS (
SELECT *,
CASE
WHEN #Qty >= TotalQty THEN QtyRec
ELSE #Qty - ISNULL(LAG(TotalQty) OVER (PARTITION BY SKU ORDER BY Id), 0)
END AS TakeQty
FROM sumqty
)
SELECT ROW_NUMBER() OVER(ORDER BY Expiry) AS 'SN'
, SKU
, QtyRec
, Expiry
, Rec
, TotalQty
, TakeQty
FROM takeqty WHERE TakeQty > 0
ORDER BY Expiry;

SQL Query-Group by and filters

I have the table as shown in below image.
I am trying to get the latest status_id, grouped by team_id and based on max of created_date.
--Latest status for each team based on created date
SELECT *
FROM ProductionHistory
WHERE created_Date IN (
SELECT MAX(created_Date)
FROM ProductionHistory
GROUP BY TeamID
)
That's fine, here is the result:
My questions are:
How to ignore the assigned_to null then find latest record for team?
When there is only one record with assigned_to null for team, let's consider that.
For example: for Team_id 5 there is only one record with assigned_to null, we don't have any other record for team_id 5 with assigned_to set some value.
So we have consider this.
For team id 3 query result should ignore the record 4 (though max date), query result should contain record 2.
Here is the final result I am expecting:
Try this:
DECLARE #t TABLE
(
TicketID INT ,
TeamID INT ,
StatusID INT ,
created_Date DATETIME ,
Assigned_to NVARCHAR(MAX)
)
INSERT #t
VALUES ( 10000, 2, 7, '2015-03-26 01:48:00.000', 'W3ER45' ),
( 10000, 3, 7, '2015-03-26 05:48:00.000', 'YU67IO' ),
( 10000, 2, 9, '2015-03-26 03:48:00.000', 'HJKO98' ),
( 10000, 3, 9, '2015-03-27 03:48:00.000', NULL ),
( 10000, 4, 11, '2015-03-23 03:48:00.000', 'GHR67' ),
( 10000, 5, 11, '2015-03-27 02:12:56.910', NULL );
;
WITH cte
AS ( SELECT * ,
ROW_NUMBER() OVER ( PARTITION BY TicketID, TeamID ORDER BY CASE
WHEN Assigned_to IS NULL
THEN 1
ELSE 0
END, created_Date DESC ) AS rn
FROM #t
)
SELECT TicketID ,
TeamID ,
StatusID ,
created_Date ,
Assigned_to
FROM cte
WHERE rn = 1
Output:
TicketID TeamID StatusID created_Date Assigned_to
10000 2 9 2015-03-26 03:48:00.000 HJKO98
10000 3 7 2015-03-26 05:48:00.000 YU67IO
10000 4 11 2015-03-23 03:48:00.000 GHR67
10000 5 11 2015-03-27 02:12:56.910 NULL
Try this answer.I did it with cursor
DECLARE #t TABLE ( TicketID INT
, TeamID INT
, StatusID INT
, created_Date DATETIME
, Assigned_to NVARCHAR(MAX) )
DECLARE cur CURSOR READ_ONLY FAST_FORWARD
FOR SELECT [TeamID]
FROM TT
DECLARE #i int
OPEN cur
FETCH NEXT FROM cur INTO #i
WHILE ##FETCH_STATUS=0
BEGIN
IF (SELECT COUNT_BIG([TeamID])
FROM TT
WHERE [TeamID]=#i)>1
BEGIN
INSERT INTO #T
SELECT TOP 1 *
FROM [dbo].[TT]
WHERE [TeamID]=#i AND [Assigned_to] IS NOT NULL
ORDER BY [created_Date] DESC
END
ELSE
BEGIN
INSERT INTO #T
SELECT *
FROM [dbo].[TT]
WHERE [TeamID]=#i
END
FETCH NEXT FROM cur INTO #i
END
SELECT TicketID
, TeamID
, StatusID
, Assigned_to
, created_Date
FROM #T
GROUP BY TicketID
, TeamID
, StatusID
, created_Date
, Assigned_to
CLOSE cur
DEALLOCATE cur