Write a faster stored procedure in SQL Server? - sql-server
I need more than 500000 rows that are stored in several tables. Getting all rows with my logic.
In this situation I write a stored procedure that is successfully executed in SQL Server browser, but when I run it from my C# code, a timeout exception occurred.
Can anyone suggest how I can improve my stored procedure?
CREATE PROCEDURE [dbo].[SP_ExtendedPTU]
(
#SQLForPTU as varchar(MAX)
)
AS
BEGIN TRAN
--DECLARE
--#SQLForPTU as varchar(MAX)
--SET #SQLForPTU= 'WHERE OrderID IN(4233)And OrderType =3'
BEGIN--1
DECLARE
#ProductionTracingUnitID as int,
#OrderID as int,
#OrderType as smallint,
#ProductID as int,
#LabLabDipID as int,
#ColorName as varchar(255),
#PantonNo as varchar(127),
#Shade as varchar(4),
#DyeingOrderQty as decimal(30, 17),
#JobOrderQty as decimal(30, 17),
#ProductionPipeLineQty as decimal(30, 17),
#ProductionFinishedQty as decimal(30, 17),
#DeliveryQty as decimal(30, 17),
#BuyerID as int,
#FactoryID as int,
#ProductionGraceQty as decimal(30, 17),
#WeightLossGainQty as decimal(30, 17),
#RateInLBS as decimal(30, 17),
#State as smallint,
#ProductionLossQty as decimal(30, 17),
#ReturnQty as decimal(30, 17),
#ActualDeliveryQty as decimal(30,17),
#ReadyStockInhand as decimal(30, 17),
#JobOrderQtyApproved as decimal(30, 17),
#OrderNumber as varchar(50),
#FactoryName as varchar(200),
#BuyerName as varchar(200),
#ProductName as varchar(200),
#YetToDelivery as decimal(30,17),
#StockInHand as decimal(30,17),
#YetToProduction as decimal(30,17),
#LCID as int,
#LCNo as varchar(300),
#PIQty as decimal(30,17),
#ChangingQty as decimal(30,17),
#SampleAdjQty as decimal(30,17),
#SampleAdjValue as decimal(30,17),
#MKTPersonID as int,
#MKTPersonName as varchar(500),
#MerchandiserID as int,
#MerchandiserName as varchar(500),
#AmendmentStatus as smallint,
#AcceptanceValue as decimal(30,17),
#MaturityValue as decimal(30,17),
#BillAcceptanceValue as decimal(30,17),
#BillMaturityValue as decimal(30,17),
#BillAcceptancePercentage as decimal(30,17),
#BillMaturityPercentage as decimal(30,17),
#ExportLCValue as decimal(30,17),
#Acceptance as varchar(100),
#Maturity as varchar(100),
#YarnCount as varchar(50),
#PTUDQty as decimal(30,17),
#ShadeFromOrder as smallint,
#EWYDLRelabNo as varchar(100),
#EWYDLColorNo as varchar(100),
#DeliveryTo as int,
#FactoryPersonnelID as int,
#BuyerPersonnelID as int,
#OrderRcvBy as int,
#OrderState as smallint
CREATE TABLE #TempTableOne(
ProductionTracingUnitID int,
OrderID int,
OrderType smallint,
ProductID int,
DyeingOrderQty decimal(30,17),
JobOrderQty decimal(30,17),
ProductionPipeLineQty decimal(30,17),
ProductionFinishedQty decimal(30,17),
DeliveryQty decimal(30,17),
BuyerID int,
FactoryID int,
ProductionGraceQty decimal(30,17),
WeightLossGainQty decimal(30,17),
RateInLBS decimal(30,17),
ProductionLossQty decimal(30,17),
ActualDeliveryQty decimal(30,17),
ReadyStockInhand decimal(30,17),
OrderNumber varchar(50),
FactoryName varchar(200),
BuyerName varchar(200),
ProductName varchar(200),
ColorName varchar(200),
LabLabDipID int,
ReturnQty decimal(30,17),
YetToDelivery decimal(30,17),
StockInHand decimal(30,17),
YetToProduction decimal(30,17),
LCID int,
LCNo varchar(300),
PIQty decimal(30,17),
ChangingQty decimal(30,17),
SampleAdjQty decimal(30,17),
SampleAdjValue decimal(30,17),
MKTPersonID int,
MKTPersonName varchar(500),
MerchandiserID int,
MerchandiserName varchar(500),
AmendmentStatus smallint,
Acceptance varchar(100),
Maturity varchar(100),
YarnCount varchar(50),
EWYDLRelabNo varchar(50),
EWYDLColorNo varchar(50),
ShadeFromOrder smallint
)
--ProductionTracingUnitID,OrderID,OrderType,ProductID,LabLabDipID,ColorName,PantonNo,EWYDLColorNo,Shade,EWYDLRelabNo,DyeingOrderQty,JobOrderQty,ProductionPipeLineQty,ProductionFinishedQty,DeliveryQty,BuyerID,FactoryID,ProductionGraceQty,WeightLossGainQty,RateInLBS,State,ProductionLossQty,ShadeFromOrder,ReturnQty,ActualDeliveryQty,ReadyStockInhand,JobOrderQtyApproved
DECLARE
#SQL as varchar(MAX)
SET #SQL=
'
DECLARE Cur_AB1 CURSOR GLOBAL FORWARD_ONLY KEYSET FOR
SELECT ProductionTracingUnitID,OrderID,OrderType,ProductID,DyeingOrderQty,JobOrderQty,ProductionPipeLineQty,ProductionFinishedQty,BuyerID,FactoryID,ProductionGraceQty,WeightLossGainQty,RateInLBS,ProductionLossQty,ActualDeliveryQty,ReadyStockInhand,ColorName,LabLabDipID,ReturnQty,EWYDLRelabNo,EWYDLColorNo,ShadeFromOrder FROM ProductionTracingUnit '+#SQLForPTU+'
'
EXEC (#SQL)
OPEN Cur_AB1
FETCH NEXT FROM Cur_AB1 INTO #ProductionTracingUnitID,#OrderID,#OrderType,#ProductID,#DyeingOrderQty,#JobOrderQty,#ProductionPipeLineQty,#ProductionFinishedQty,#BuyerID,#FactoryID,#ProductionGraceQty,#WeightLossGainQty,#RateInLBS,#ProductionLossQty,#ActualDeliveryQty,#ReadyStockInhand,#ColorName,#LabLabDipID,#ReturnQty,#EWYDLRelabNo,#EWYDLColorNo,#ShadeFromOrder
WHILE(##Fetch_Status <> -1)
BEGIN--2
SET #LCID=0
SET #LCNo=''
SET #PIQty=0
SET #AcceptanceValue =0
SET #MaturityValue= 0
SET #Acceptance= ''
SET #Maturity =''
SET #DeliveryQty=#ActualDeliveryQty-#ReturnQty
SET #YetToDelivery=#JobOrderQty-#ActualDeliveryQty+#ReturnQty
set #PTUDQty=(select sum(Qty) from PTUDistribution where ProductionTracingUnitID=#ProductionTracingUnitID )
IF(#PTUDQty>#YetToDelivery)
BEGIN--sih
SET #StockInHand =#YetToDelivery
END --sih
ELSE
BEGIN--sih2
SET #StockInHand =#PTUDQty
END --sih2
SET #YetToProduction=#JobOrderQty-#ReadyStockInhand-#ActualDeliveryQty+#ReturnQty
IF (#YetToProduction<0)
BEGIN
SET #YetToProduction=0
END
SET #ChangingQty=0
SET #SampleAdjQty=0
SET #SampleAdjValue=0
SET #MerchandiserID=0
SET #MerchandiserName=''
SET #MKTPersonID =0
SET #AmendmentStatus=0
SET #AcceptanceValue =0
SET #MaturityValue= 0
SET #Acceptance= ''
SET #Maturity =''
SET #MKTPersonName =''
SET #OrderNumber=''
IF(#OrderType=3)
BEGIN--jam1
SET #OrderNumber=(SELECT ISNULL(JobCode,'')+' - '+ISNULL(JobNo,'')+' / '+ISNULL(JobYear,'') FROM Job WHERE JobID=#OrderID)
SELECT #LCID=ISNULL(ExportLCID,0), #LCNo=ISNULL(ExportLCNo,''),#AmendmentStatus=AmendmentStatus,#ExportLCValue=Amount FROM ExportLC WHERE ExportLCID =(SELECT LCID FROM [PI] WHERE PIID=(SELECT PIID FROM Job WHERE JobID=#OrderID))
SELECT #PIQty=ISNULL(SUM(Qty),0), #SampleAdjQty=ISNULL(SUM(AdjQty),0), #SampleAdjValue=ISNULL(SUM(AdjValue),0) FROM PIProducts WHERE PIID=(SELECT PIID FROM Job WHERE JobID=#OrderID) AND ProductID=#ProductID
SET #ChangingQty=(SELECT ISNULL(SUM(Qty),0) FROM PIDeliverableProducts WHERE PIID=(SELECT PIID FROM Job WHERE JobID=#OrderID) AND ProductID=#ProductID)
SELECT #MKTPersonID=EWYDLMarketingEmpID, #MerchandiserID=CmsBCPID FROM [PI] WHERE PIID=(SELECT PIID FROM Job WHERE JobID=#OrderID)
SET #MerchandiserName=(SELECT ISNULL([Name],'') FROM ContactPersonnel WHERE ContactPersonnelID=#MerchandiserID)
SET #MKTPersonName =(SELECT [Name] FROM Employee WHERE EmployeeID=#MKTPersonID)
SET #BillAcceptanceValue=(select isnull(sum(Amount),0) from LCbill where EXportLCID=#LCID and [state] in (2,3,4))
SET #BillMaturityValue =(select isnull(sum(Amount),0) from LCbill where EXportLCID=#LCID and [state] in (5,6,7,8,9,10,12))
IF(#ExportLCValue>0 and #ExportLCValue is not null)
BEGIN
SET #BillAcceptancePercentage =(#BillAcceptanceValue*100)/#ExportLCValue -- bill Percentage
SET #BillMaturityPercentage =(#BillMaturityValue*100)/#ExportLCValue
SET #AcceptanceValue=(#ChangingQty*#RateInLBS)*(#BillAcceptancePercentage/100)--Percentage Wise PI Valu
SET #MaturityValue=(#ChangingQty*#RateInLBS)*(#BillMaturityPercentage/100)
IF((#ChangingQty*#RateInLBS)>0 and (#ChangingQty*#RateInLBS) is not null)
BEGIN
SET #AcceptanceValue=(#AcceptanceValue*100)/(#ChangingQty*#RateInLBS)-- PI ValuePercentage
SET #MaturityValue=(#MaturityValue*100)/(#ChangingQty*#RateInLBS)
END
SET #Acceptance=Convert(varchar(20),(CONVERT(float,round((#AcceptanceValue+#MaturityValue),0)))) +'%'
SET #Maturity =Convert(varchar(20),(CONVERT(float,round(#MaturityValue,0)))) +'%'
END
SET #FactoryName=''
IF(#FactoryID>0)
BEGIN--jam3
SET #FactoryName=(SELECT [Name] FROM Contractor WHERE ContractorID=#FactoryID)
END--jam3
SET #BuyerName=''
IF(#BuyerID>0)
BEGIN--jam4
SET #BuyerName=(SELECT [Name] FROM Contractor WHERE ContractorID=#BuyerID)
END--jam4
END--jam1
ELSE
BEGIN --jam2 IF Sample
SET #LCID=0
SET #LCNo=''
SET #OrderNumber=''
SET #PIQty=0
SET #DeliveryTo=0
SET #FactoryPersonnelID=0
SET #BuyerPersonnelID=0
SET #OrderRcvBy=0
SET #ChangingQty=0
SET #MerchandiserName=''
SET #MKTPersonName=''
SET #OrderState=0
SET #AmendmentStatus=0
SET #PIQty= (SELECT ISNULL(SUM(Qty),0) FROM SampleOrderDetail WHERE PTUID=#ProductionTracingUnitID)
SET #ChangingQty=#PIQty
SELECT #OrderNumber=ISNULL(SampleOrderNo,''), #DeliveryTo=ISNULL(DeliveryTo,0),#FactoryPersonnelID=ISNULL(FactoryPersonnelID,0),#BuyerPersonnelID=ISNULL(BuyerPersonnelID,0),#OrderRcvBy=ISNULL(OrderRcvBy,0),#OrderState=ISNULL(OrderState,0) FROM SampleOrder WHERE SampleOrderID=#OrderID
SET #AmendmentStatus=#OrderState
IF(#DeliveryTo=3)
BEGIN
SET #MerchandiserName=(SELECT ISNULL([Name],'') FROM ContactPersonnel WHERE ContactPersonnelID=#FactoryPersonnelID)
END
IF(#DeliveryTo=2)
BEGIN
SET #MerchandiserName=(SELECT ISNULL([Name],'') FROM ContactPersonnel WHERE ContactPersonnelID=#BuyerPersonnelID)
END
SET #MKTPersonName =(SELECT [Name] FROM Employee WHERE EmployeeID=#OrderRcvBy)
IF(#DeliveryTo=3)
BEGIN
SET #FactoryName=(SELECT [Name] FROM Contractor WHERE ContractorID=#FactoryID)
END
IF(#DeliveryTo=2)
BEGIN
SET #FactoryName=(SELECT [Name] FROM Contractor WHERE ContractorID=#BuyerID)
END
SET #BuyerName=''
IF(#BuyerID>0)
BEGIN--jam4
SET #BuyerName=(SELECT [Name] FROM Contractor WHERE ContractorID=#BuyerID)
END--jam4
END--jam2
SET #ProductName=''
SET #YarnCount =''
SELECT #ProductName=('['+ Code+ '] '+ [Name]), #YarnCount =[Count] FROM Yarncategory WHERE YarncategoryID=#ProductID
INSERT INTO #TempTableOne Values(ISNULL(#ProductionTracingUnitID,0),ISNULL(#OrderID,0),ISNULL(#OrderType,0),ISNULL(#ProductID,0),ISNULL(#DyeingOrderQty,0),ISNULL(#JobOrderQty,0),ISNULL(#ProductionPipeLineQty,0),ISNULL(#ProductionFinishedQty,0),ISNULL(#DeliveryQty,0),ISNULL(#BuyerID,0),ISNULL(#FactoryID,0),ISNULL(#ProductionGraceQty,0),ISNULL(#WeightLossGainQty,0),ISNULL(CONVERT (decimal(18,2),#RateInLBS),0),ISNULL(#ProductionLossQty,0),ISNULL(#ActualDeliveryQty,0),ISNULL(#ReadyStockInhand,0),ISNULL(#OrderNumber,''),ISNULL(#FactoryName,''),ISNULL(#BuyerName,''),ISNULL(#ProductName,''),ISNULL(#ColorName,''),ISNULL(#LabLabDipID,0),ISNULL(#ReturnQty,0),ISNULL(#YetToDelivery,0),ISNULL(#StockInHand,0),ISNULL(#YetToProduction,0),ISNULL(#LCID,0),ISNULL(#LCNo,''),ISNULL(#PIQty,0),ISNULL(#ChangingQty,0),ISNULL(#SampleAdjQty,0),ISNULL(#SampleAdjValue,0),ISNULL(#MKTPersonID,0),ISNULL(#MKTPersonName,''),ISNULL(#MerchandiserID,0),ISNULL(#MerchandiserName,''),ISNULL(#AmendmentStatus,0),ISNULL(#Acceptance,''),ISNULL(#Maturity,''),ISNULL(#YarnCount,''),ISNULL(#EWYDLRelabNo,''),ISNULL(#EWYDLColorNo,''),ISNULL(#ShadeFromOrder,0))
FETCH NEXT FROM Cur_AB1 INTO #ProductionTracingUnitID,#OrderID,#OrderType,#ProductID,#DyeingOrderQty,#JobOrderQty,#ProductionPipeLineQty,#ProductionFinishedQty,#BuyerID,#FactoryID,#ProductionGraceQty,#WeightLossGainQty,#RateInLBS,#ProductionLossQty,#ActualDeliveryQty,#ReadyStockInhand,#ColorName,#LabLabDipID,#ReturnQty,#EWYDLRelabNo,#EWYDLColorNo,#ShadeFromOrder
END--2
CLOSE Cur_AB1
DEALLOCATE Cur_AB1
SELECT * FROM #TempTableOne Order By OrderID
--Group By Product
SELECT ProductID,ProductName, YarnCount, SUM(PIQty) as PIQty, SUM(ChangingQty) AS ChangingQty, SUM(SampleAdjQty) AS SampleAdjQty, SUM(SampleAdjValue) as SampleAdjValue, SUM(DyeingOrderQty) as DyeingOrderQty,SUM(JobOrderQty)AS JobOrderQty,SUM(ProductionPipeLineQty)as ProductionPipeLineQty,SUM(ProductionFinishedQty) as ProductionFinishedQty,SUM(DeliveryQty)as DeliveryQty,SUM(ProductionGraceQty)AS ProductionGraceQty,SUM(WeightLossGainQty) as WeightLossGainQty,SUM(ProductionLossQty)as ProductionLossQty,SUM(ActualDeliveryQty)as ActualDeliveryQty,SUM(ReadyStockInhand)as ReadyStockInhand, SUM(ReturnQty) AS ReturnQty,SUM(YetToDelivery)AS YetToDelivery,SUM(StockInHand)AS StockInHand,SUM(YetToProduction)AS YetToProduction FROM #TempTableOne GROUP BY ProductID,ProductName,YarnCount Order By ProductID
--Group By Factory
SELECT FactoryID,FactoryName,SUM(PIQty) as PIQty, SUM(ChangingQty) AS ChangingQty, SUM(SampleAdjQty) AS SampleAdjQty, SUM(SampleAdjValue) as SampleAdjValue, SUM(DyeingOrderQty) as DyeingOrderQty,SUM(JobOrderQty)AS JobOrderQty,SUM(ProductionPipeLineQty)as ProductionPipeLineQty,SUM(ProductionFinishedQty) as ProductionFinishedQty,SUM(DeliveryQty)as DeliveryQty,SUM(ProductionGraceQty)AS ProductionGraceQty,SUM(WeightLossGainQty) as WeightLossGainQty,SUM(ProductionLossQty)as ProductionLossQty,SUM(ActualDeliveryQty)as ActualDeliveryQty,SUM(ReadyStockInhand)as ReadyStockInhand, SUM(ReturnQty) AS ReturnQty,SUM(YetToDelivery)AS YetToDelivery,SUM(StockInHand)AS StockInHand,SUM(YetToProduction)AS YetToProduction FROM #TempTableOne GROUP BY FactoryID,FactoryName
--Group By Order
SELECT OrderID,OrderNumber,LCNo,FactoryID,FactoryName,BuyerID,BuyerName,SUM(PIQty) AS PIQty,SUM(ChangingQty) AS ChangingQty,SUM(SampleAdjQty) AS SampleAdjQty,SUM(SampleAdjValue) AS SampleAdjValue,MKTPersonID,MKTPersonName,MerchandiserID,MerchandiserName,AmendmentStatus,Acceptance,Maturity,SUM(DyeingOrderQty) as DyeingOrderQty,SUM(JobOrderQty)AS JobOrderQty,SUM(ProductionPipeLineQty)as ProductionPipeLineQty,SUM(ProductionFinishedQty) as ProductionFinishedQty,SUM(DeliveryQty)as DeliveryQty,SUM(ProductionGraceQty)AS ProductionGraceQty,SUM(WeightLossGainQty) as WeightLossGainQty,SUM(ProductionLossQty)as ProductionLossQty,SUM(ActualDeliveryQty)as ActualDeliveryQty,SUM(ReadyStockInhand)as ReadyStockInhand, SUM(ReturnQty) AS ReturnQty,SUM(YetToDelivery)AS YetToDelivery,SUM(StockInHand)AS StockInHand,SUM(YetToProduction)AS YetToProduction FROM #TempTableOne GROUP BY OrderID,OrderNumber,OrderNumber,LCNo,FactoryID,FactoryName,BuyerID,BuyerName,MKTPersonID,MKTPersonName,MerchandiserID,MerchandiserName,AmendmentStatus,Acceptance,Maturity
--Default View
SELECT OrderID,OrderNumber,LCNo,FactoryID,FactoryName,BuyerID,BuyerName,ProductID,ProductName,YarnCount,PIQty,ChangingQty,SampleAdjQty,SampleAdjValue,RateInLBS,MKTPersonID,MKTPersonName,MerchandiserID,MerchandiserName,AmendmentStatus,Acceptance,Maturity, SUM(DyeingOrderQty) as DyeingOrderQty,SUM(JobOrderQty)AS JobOrderQty,SUM(ProductionPipeLineQty)as ProductionPipeLineQty,SUM(ProductionFinishedQty) as ProductionFinishedQty,SUM(DeliveryQty)as DeliveryQty,SUM(ProductionGraceQty)AS ProductionGraceQty,SUM(WeightLossGainQty) as WeightLossGainQty,SUM(ProductionLossQty)as ProductionLossQty,SUM(ActualDeliveryQty)as ActualDeliveryQty,SUM(ReadyStockInhand)as ReadyStockInhand, SUM(ReturnQty) AS ReturnQty,SUM(YetToDelivery)AS YetToDelivery,SUM(StockInHand)AS StockInHand,SUM(YetToProduction)AS YetToProduction FROM #TempTableOne GROUP BY OrderID,OrderNumber,LCNo,FactoryID,FactoryName,BuyerID,BuyerName,ProductID,ProductName,YarnCount,PIQty,ChangingQty,SampleAdjQty,SampleAdjValue,RateInLBS,MKTPersonID,MKTPersonName,MerchandiserID,MerchandiserName,AmendmentStatus,Acceptance,Maturity
DROP TABLE #TempTableOne
END--1
COMMIT TRAN
There are a host of issues here. Properly written, this procedure should run comfortably in about 15 seconds, depending on your indexes. The tips I can give you before I delve into detail are as follows:
First up, the only time that it is acceptable to use cursors when doing bulk processing is for partitioning updates in the bulk process. In other words, never use a cursor that needs to iterate for every record to be updated. The entire procedure needs to iterate 500,000 times, and that is going to be very slow. Rather use a temp table to insert the data into, and then use that table to perform updates on. It is possible to index a temporary table with temporary indexes, as shown in the code below. Make sure that any fields used in a WHERE clause is indexed, both for your temp tables and your live tables.
CREATE TABLE #Temp2 (
ProductionTracingUnitID int,
OrderID int,
OrderType smallint,
ProductID int,
DyeingOrderQty decimal(30, 17),
JobOrderQty decimal(30, 17),
ProductionPipeLineQty decimal(30, 17),
ProductionFinishedQty decimal(30, 17),
BuyerID int,
FactoryID int,
ProductionGraceQty decimal(30, 17),
WeightLossGainQty decimal(30, 17),
RateInLBS decimal(30, 17),
ProductionLossQty decimal(30, 17),
ActualDeliveryQty decimal(30,17),
ReadyStockInhand decimal(30, 17),
ColorName varchar(255),
LabLabDipID int,
ReturnQty decimal(30, 17),
EWYDLRelabNo varchar(100),
EWYDLColorNo varchar(100),
ShadeFromOrder smallint
)
CREATE NONCLUSTERED INDEX #IX_Temp2_1 ON #Temp2(ProductionTracingUnitID)
CREATE NONCLUSTERED INDEX #IX_Temp2_2 ON #Temp2(OrderID)
CREATE NONCLUSTERED INDEX #IX_Temp2_3 ON #Temp2(ProductID)
DECLARE #SQL as varchar(MAX)
SET #SQL=
'
SELECT ProductionTracingUnitID,OrderID,OrderType,ProductID,DyeingOrderQty,JobOrderQty,ProductionPipeLineQty,ProductionFinishedQty,BuyerID,FactoryID,ProductionGraceQty,
WeightLossGainQty,RateInLBS,ProductionLossQty,ActualDeliveryQty,ReadyStockInhand,ColorName,LabLabDipID,ReturnQty,EWYDLRelabNo,EWYDLColorNo,ShadeFromOrder
FROM ProductionTracingUnit '+#SQLForPTU
INSERT INTO #Temp2 (ProductionTracingUnitID, OrderID, OrderType, ProductID, DyeingOrderQty, JobOrderQty, ProductionPipeLineQty,
ProductionFinishedQty, BuyerID, FactoryID, ProductionGraceQty, WeightLossGainQty, RateInLBS, ProductionLossQty, ActualDeliveryQty,
ReadyStockInhand, ColorName, LabLabDipID, ReturnQty, EWYDLRelabNo, EWYDLColorNo, ShadeFromOrder)
EXEC (#SQL)
Next, when doing bulk processing, avoid the use of sub-queries that need to be executed per row. The following line would be very slow, at the best of times:
SELECT #LCID=ISNULL(ExportLCID,0), #LCNo=ISNULL(ExportLCNo,''),#AmendmentStatus=AmendmentStatus,#ExportLCValue=Amount
FROM ExportLC WHERE ExportLCID =(SELECT LCID FROM [PI] WHERE PIID=(SELECT PIID FROM Job WHERE JobID=#OrderID))
Consider rephrasing with joins, like this:
SELECT #LCID=ISNULL(ExportLCID,0), #LCNo=ISNULL(ExportLCNo,''),#AmendmentStatus=AmendmentStatus,#ExportLCValue=Amount
FROM ExportLC e, [PI] p, Job j
WHERE e.ExportLCID = p.LCID
AND p.PIID = j.PIID
AND j.JobID = #OrderID
Rewriting the procedure without the use of a cursor, this would look more along the lines of:
UPDATE #Temp2 SET LCID = ISNULL(ExportLCID, 0), LCNo = ISNULL(ExportLCNo, 0), ...
FROM #Temp2 t, ExportLC e, [PI] p, Job j
WHERE e.ExportLCID = p.LCID
AND p.PIID = j.PIID
AND j.JobID = t.OrderID
There is quite a bit of work to get this all working, and it is difficult for me to create a test environment for a such a compound process. However, I think this should give you enough to go on. Let me know if you get stuck.
You can use the execution plan in SQL Server to identify the bottlenecks.
Also please try to avoid using cursors if possible and also if the temp table contains huge amount of data, create a normal table instead of creating a #table
If you are parsing 500,000 rows a cursor is a non starter. This will cause all sorts of problems and as your data grows, it will become slower and slower. There are several ways to achieve better performance.
1) If possible, fetch data overnight - i.e. flattening the data into a snapshot table using a SQL job
2) Fetch as much data as possible in a batch select - i.e. rather than inserting into your temp table row by row in your loop, you can do a query to get all the data you need for a particular column
3) If you cannot do this overnight and it must always be done like this, I would suggest breaking this up into discreet Stored Procedures and looping from within your C# code. That way you can provide feedback to your user - perhaps in the form of a progress bar. This won't timeout, and it won't really matter how long it takes provided the user is aware something is being calculated, they get a rough idea of how long they have to wait, and they have a chance to back out if they want to.
Related
Using SQL Exists but having issues
I have a stored procedure which inserts records from a lab, and for months it has been inserting records and working. But in the last month something has changed and my record check stopped working. The SampleNames exist and I can do a query to locate the sample name. What might be the issue? I can get it to sort of work if I replace the If Exists with this: IF EXISTS (SELECT [SampleName] FROM [dbo].[HPLC_Sample] WHERE [SampleName] LIKE '%' + UPPER(#SampleName) + '%') SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [dbo].[sp_HPLC_Params] #SampleName nvarchar(32), #DataFile nvarchar(max), #AcqInstrument nvarchar(50), #AnalysisDate datetime, #ResultsCreated datetime, #ResCreatedBy nvarchar(50), #AcqMethod nvarchar(50), #InjDate datetime, #AcqOp datetime, #SeqLine int, #Location int, #Inj int, #InjVol int, #ActualInj int, #SeqFile nvarchar(50), #StartPress float, #StopPress float, #StartFlow float, #StopFlow float, #SortBy nvarchar(50), #CalbDTCreate datetime, #CalbDTMod datetime, #PeakID nchar(10), #Muliplier int, #Dilution int, #UnCalPeaks nchar(10), #NumSignals int, #NumErrors int AS BEGIN DECLARE #SampleID AS smallint IF EXISTS (SELECT [SampleName] FROM [dbo].[HPLC_Sample] WHERE [SampleName] = #SampleName) BEGIN SELECT #SampleID = [SampleID] FROM [dbo].[HPLC_Sample] WHERE [SampleName] = #SampleName END ELSE BEGIN INSERT INTO HPLC_Sample([SampleName]) VALUES (UPPER(#SampleName)) SELECT #SampleID = [SampleID] FROM [dbo].[HPLC_Sample] WHERE [SampleName] = #SampleName END END BEGIN SET NOCOUNT ON; BEGIN INSERT INTO HPLC_Params([SampleID], [Data File], [Acq Instrument], [Analysis Date], [Results Created], [Results Created By], [Acq Method], [Injection Date], [Acq Operator], [Seq Line], [Location], [Inj], [Inj Volume], [Actual Inj Volume], [Sequence File], [Start Pressure], [Stop Pressure], [Start Flow], [Stop Flow], [Sorted By], [Calib Data Created], [Calib Data Modified], [Peak ID], [Multiplier],[Dilution], [Uncalibrated Peaks], [Number of Signals], [Number of Errors]) VALUES (#SampleID, #DataFile, #AcqInstrument, #AnalysisDate, #ResultsCreated, #ResCreatedBy, #AcqMethod, #InjDate, #AcqOp, #SeqLine, #Location, #Inj, #InjVol, #ActualInj, #SeqFile, #StartPress, #StopPress, #StartFlow, #StopFlow, #SortBy, #CalbDTCreate, #CalbDTMod, #PeakID, #Muliplier, #Dilution, #UnCalPeaks, #NumSignals, #NumErrors) END END
Verification of adding an identical record in SQL
I need support, I have a procedure and I need it to return an error when I try to add the same name in the ProductName column: USE [Northwind] GO /****** Object: StoredProcedure [dbo].[AddNewProduct] Script Date: 14.09.2021 18:15:53 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER procedure [dbo].[AddNewProduct] #ProductName nvarchar(40), #SupplierID int, #CategoryID int, #QuantityPerUnit nvarchar(20), #UnitPrice money, #UnitsInStock smallint, #UnitsOnOrder smallint, #ReorderLevel smallint, #Discontinued bit as If #ProductName = #ProductName Begin Declare #count int, #ProductID int Insert into Products ( ProductName , SupplierID , CategoryID , QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued) values (#ProductName, #SupplierID , #CategoryID , #QuantityPerUnit, #UnitPrice, #UnitsInStock, #UnitsOnOrder, #ReorderLevel, #Discontinued ) End else Begin DECLARE #ErrorMessage NVARCHAR(4000); SET #ErrorMessage = 'DDDD'; RAISERROR (#ErrorMessage, 16, 1); end I want a message to appear when I try to add the same record Can you tell me what I am doing wrong or what needs to be added / changed?
As has been mentioned in the comments, this logic has no right being in the procedure, it should be part of the table's definition, as a UNIQUE CONSTRAINT or UNIQUE INDEX. I'm going to use a UNIQUE CONSTRAINT here, which would mean the DDL for the CONSTRAINT would look like this: ALTER TABLE dbo.Products ADD CONSTRAINT UQ_ProductName UNIQUE (ProductName); Then, you just need your procedure to look like this: ALTER PROCEDURE [dbo].[AddNewProduct] #ProductName nvarchar(40), #SupplierID int, #CategoryID int, #QuantityPerUnit nvarchar(20), --Why is this an nvarchar if it's a quantity? #UnitPrice money, #UnitsInStock smallint, #UnitsOnOrder smallint, #ReorderLevel smallint, #Discontinued bit AS BEGIN INSERT INTO dbo.Products(ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued) VALUES (#ProductName, #SupplierID, #CategoryID, #QuantityPerUnit, #UnitPrice, #UnitsInStock, #UnitsOnOrder, #ReorderLevel, #Discontinued); END; GO If you then attempt to insert a duplicate value you'll get the following error: Violation of UNIQUE KEY constraint 'UQ_ProductName'. Cannot insert duplicate key in object 'dbo.Products'. The duplicate key value is ({Duplicate Product Name}).
Simple insert stored procedure not working
I am trying to make a simple stored procedure but it's not working. When I execute the procedure with my parameters in it, below is the following: ALTER proc [dbo].[sp_NewProduct] #ProductName nvarchar(50), #ProductNumber nvarchar(25), #MakeFlag bit, #FinishedGoodsFlag bit, #Color nvarchar(15), #SafetyStockLevel smallint, #ReorderPoint smallint, #StandardCost money, #ListPrice money, #DaysToManufacture int, #SellStartDate date, #rowguid uniqueidentifier, #ModifiedDate datetime as insert dbo.product (Name, ProductNumber, MakeFlag, FinishedGoodsFlag, Color, SafetyStockLevel, ReorderPoint, StandardCost, ListPrice, DaysToManufacture, SellStartDate, rowguid, ModifiedDate) values (#ProductName, #ProductNumber, #MakeFlag, #FinishedGoodsFlag, #Color, #SafetyStockLevel, #ReorderPoint, #StandardCost, #ListPrice, #DaysToManufacture, #SellStartDate, #rowguid, #ModifiedDate) Here's the execute query with values of each column: exec sp_NewProduct 'AR-5516','105',0,1,'Red',5,5,0.00,0.00,5,'2018-05-01',newid(),getdate()
Seems you are dealing with wrong procedure syntax! use following snippets: Create or Alter proc [dbo].[sp_NewProduct] (#ProductName nvarchar(50), #ProductNumber nvarchar(25), #MakeFlag bit, #FinishedGoodsFlag bit, #Color nvarchar(15), #SafetyStockLevel smallint, #ReorderPoint smallint, #StandardCost money, #ListPrice money, #DaysToManufacture int, #SellStartDate date, #rowguid uniqueidentifier, #ModifiedDate datetime) As Begin Insert dbo.product (Name,ProductNumber,MakeFlag,FinishedGoodsFlag,Color,SafetyStockLevel,ReorderPoint,StandardCost,ListPrice, DaysToManufacture,SellStartDate,rowguid,ModifiedDate) values (#ProductName,#ProductNumber,#MakeFlag,#FinishedGoodsFlag,#Color, #SafetyStockLevel,#ReorderPoint,#StandardCost,#ListPrice,#DaysToManufacture,#SellStartDate,#rowguid,#ModifiedDate) End Go Exec sp_NewProduct 'AR-5516','105',0,1,'Red',5,5,0.00,0.00,5,'2018-05-01',#Id,#DateTime; If you still getting error, store newid()'s value and GetDate()'s value in temporary variable, and call through this variable! Declare #Id AS UniqueIdentifier = NewId() Declare #DateTime as DateTime = GetDate() Exec sp_NewProduct 'AR-5516','105',0,1,'Red',5,5,0.00,0.00,5,'2018-05-01',#Id,#DateTime;
SQL Server errors
Code: Declare #ParmDefinition Nvarchar(1000), #St Nvarchar(500), #TTable varchar(30) Set #TTable='[0Detail]' Declare #TTempStore Table ( Iden Int, Row_ Int, Accs_iden int, Am_Bed Money, Am_Bes Money, Doc_No Decimal(15,0), Desc_ Nvarchar(500), Checked bit, Error_ int) SET #ParmDefinition = N'#alaki table(Iden Int, Row_ Int, Accs_iden int, Am_Bed Money, Am_Bes Money, Doc_No Decimal(15,0), Desc_ Nvarchar(500),Checked bit,Error_ int) OUTPUT ' Set #St = N' Select * into #alaki from '+#TTable EXECUTE sp_executesql #St, #ParmDefinition, #alaki = #TTempStore SELECT * FROM #TTempStore Errors: Msg 156, Level 15, State 1, Line 1 Incorrect syntax near the keyword 'table'. Msg 102, Level 15, State 1, Line 1 Incorrect syntax near '#alaki'.
You should post a minimal working sample for us to be able to help you, remember that next time. Why not declare the table with #TTempStore ? Declare #St Nvarchar(500),#TTable varchar(30) Set #TTable='[0Detail]' create table #TTempStore ( Iden Int, Row_ Int, Accs_iden int, Am_Bed Money, Am_Bes Money, Doc_No Decimal(15,0), Desc_ Nvarchar(500), Checked bit, Error_ int) Set #St=N' Select * into #TTempStore from '+#TTable EXECUTE #St Select * from #TTempStore drop table #TTempStore --here you can leave the table if you have more things to do I haven't tested it, but it should point you in the right direction. If you need I can probably make a sql fiddle later.
Could the #TTable value be different every time? If it's always going to be [0Detail] then you don't need dynamic SQL. However, here is a dynamic SQL solution to your problem: Declare #St Nvarchar(500),#TTable varchar(30) Set #TTable='[0Detail]' Declare #TTempStore Table ( Iden Int, Row_ Int, Accs_iden int, Am_Bed Money, Am_Bes Money, Doc_No Decimal(15,0), Desc_ Nvarchar(500), Checked bit, Error_ int) Set #St=N' Select * from '+#TTable INSERT INTO #TTempStore EXECUTE (#St) Select * from #TTempStore
Cannot insert the value NULL into column '', table column does not allow nulls. INSERT fails
Code: ALTER PROCEDURE [dbo].[SP_LMS_dealerorusercreation_IUDS] #dealrid bigint, #rid bigint, #stateid bigint, #regonid bigint, #Locid bigint, #pid varchar(MAX), #address varchar(max), #dealrname varchar(25), #landno bigint, #mobno bigint, #altcontno bigint, #email varchar(35), #desig varchar(25), #reporting varchar(30), #status int, #action varchar(10), #CompanyId Uniqueidentifier AS DECLARE #TranStatus VARCHAR(5) BEGIN TRY BEGIN TRANSACTION IF(#action='Insert') BEGIN INSERT INTO LMS_dealerorusercreation( rid, stateid, regonid, Locid, addres, dealrname, landno, mobno, altcontno, email, desig, reporting, status, CompanyId ) VALUES( #rid, #stateid, #regonid, #Locid, #address, #dealrname, #landno, #mobno, #altcontno, #email, #desig, #reporting, #status, #CompanyId ) SELECT #dealrid = dealrid FROM LMS_dealerorusercreation WHERE mobno = #mobno AND email = #email EXEC [dbo].[SP_LMS_SetDealerProductMapping] #dealerId = #dealrid, #prodid = #pid SET #TranStatus='TRUE'; END IF(#action='Update') BEGIN UPDATE LMS_dealerorusercreation set rid= #rid, stateid=#stateid, regonid=#regonid, Locid=#Locid, addres=#address, dealrname=#dealrname, landno=#landno, mobno=#mobno, altcontno=#altcontno, email=#email, desig=#desig, reporting=#reporting, status=#status WHERE dealrid=#dealrid SET #TranStatus='TRUE'; END IF(#action='Delete') BEGIN DELETE FROM LMS_dealerorusercreation WHERE dealrid=#dealrid SET #TranStatus='TRUE'; END COMMIT TRANSACTION END TRY BEGIN CATCH ROLLBACK TRANSACTION DECLARE #AI VARCHAR(MAX) DECLARE #EM VARCHAR(MAX); SET #AI = 'Not Provided' SET #EM = ERROR_MESSAGE(); EXEC USP_SetException #ExceptionDetail = #EM, #AdditionalInfo = #AI SET #TranStatus='FALSE'; END CATCH SELECT #TranStatus; The error am getting is Cannot insert the value NULL into column 'dealrid', table 'DB_LMS.dbo.LMS_dealerorusercreation'; column does not allow nulls. INSERT fails.
You need to do one of two things, either... ensure that you pass in a non-null value for the column, or; ensure that your column accepts a null value if that is a desired property of the field.
Errors I see in the code. While inserting into the table LMS_dealerorusercreation, you never selected dealrid column. Please select the same. INSERT INTO LMS_dealerorusercreation( rid, stateid, regonid, Locid, addres, dealrname, landno, mobno, altcontno, email, desig, reporting, status, CompanyId, dealrid ) VALUES( #rid, #stateid, #regonid, #Locid, #address, #dealrname, #landno, #mobno, #altcontno, #email, #desig, #reporting, #status, #CompanyId, #dealrid )
it is juat as the error message states. you are trying to do an insert to a table where dealrid has been created with not null. if you look at your insert statement, you are not selecting and passing a value to it.