sql linked server Insert statement fails inside the cursor - sql

Insert statement fails inside the cursor when I try to insert values in to SQL linked server.
If I run the same insert statement outside cursor then it works fine. Is there any settings to be done while creating linked server?
Error message:
OLE DB provider "SQL...." for linked server "" returned message "The parameter is incorrect.".
This is my Code Linked Server in Cursor
SET NOCOUNT ON;
DECLARE #SUBCATEGORY_NAME AS VARCHAR(100), #CategoryStatus AS BIT, #BRAND_NAME AS VARCHAR(100), #BrandMasterStatus AS BIT, #BrandManfacturerName AS VARCHAR(MAX), #PRODUCT_NAME VARCHAR(100), #ProductStatus AS BIT,
#ProductIsReturnable AS BIT, #PRINT_ON_RECEIPT AS VARCHAR(40), #TenantId INT, #CreationTime DATETIME2, #ParentId INT, #BAR_CODE_NO AS VARCHAR(40),
#TAX_CODE AS VARCHAR(MAX), #TaxName AS VARCHAR(MAX), #TaxInclusive AS BIT, #TAX_PERCENTAGE AS FLOAT, #TaxStartDateTime DATETIME2, #BUSINESS_TYPE VARCHAR(20);
--PRINT '-------- Product table migration --------';
DECLARE Product_Cursor CURSOR FOR
SELECT
SC.SUBCATEGORY_NAME,CASE WHEN SC.DEFUNCT_IND = 'N' THEN 1 ELSE 0 END AS CategoryStatus,
BM.BRAND_NAME,CASE WHEN BM.DEFUNCT_IND = 'N' THEN 1 ELSE 0 END AS BrandMasterStatus,BM.MANUFACTURER AS BrandManfacturerName,
P.PRODUCT_NAME,CASE WHEN P.DEFUNCT_IND = 'N' THEN 1 ELSE 0 END AS ProductStatus,
CASE WHEN P.RETURNABLE = 'Y' THEN 1 ELSE 0 END AS ProductIsReturnable,
P.PRINT_ON_RECEIPT,
--SubCategoryId,
--BrandId,
--1 AS TaxId,
1 AS TenantId,
GETDATE() AS CreationTime,
0 AS ParentId,
P.BAR_CODE_NO,
TS.TAX_CODE,
TS.TAX_DESC AS TaxName,
CASE WHEN TS.TAX_INCLUDED = '1' THEN 1 ELSE 0 END AS TaxInclusive,
TS.TAX_PERCENTAGE,
TS.EFFECTIVE_DATE AS TaxStartDateTime,
P.BUSINESS_TYPE
FROM CISPROD.dbo.PRODUCT AS P
RIGHT OUTER JOIN CISPROD.dbo.SUBCATEGORY AS SC ON SC.SUBCATEGORY_ID = P.SUBCATEGORY_ID
FULL OUTER JOIN CISPROD.dbo.BRANDMSTR AS BM ON BM.BRANDMSTR_ID = P.BRANDMSTR_ID
FULL OUTER JOIN CISPROD.dbo.TAX_SETUP AS TS ON TS.TAX_CODE = P.TAX_GROUP
OPEN Product_Cursor
FETCH NEXT FROM Product_Cursor
INTO #SUBCATEGORY_NAME,#CategoryStatus,#BRAND_NAME, #BrandMasterStatus, #BrandManfacturerName, #PRODUCT_NAME, #ProductStatus, #ProductIsReturnable,
#PRINT_ON_RECEIPT, #TenantId, #CreationTime,#ParentId,#BAR_CODE_NO,#TAX_CODE, #TaxName, #TaxInclusive, #TAX_PERCENTAGE, #TaxStartDateTime, #BUSINESS_TYPE;
BEGIN TRANSACTION
BEGIN TRY
WHILE ##FETCH_STATUS = 0
BEGIN
--PRINT ' '
--DECLARE #message VARCHAR(MAX)
--SELECT #message = '----- Products CISPROD: ' + #PRODUCT_NAME
--PRINT #message
--Insert Product Categories Table
DECLARE #CategoryId INT
IF ISNULL(#SUBCATEGORY_NAME,'') <>''
BEGIN
---IF NOT EXISTS(SELECT [Name] FROM ProductCategories WHERE ISNULL([Name], '') = ISNULL(#SUBCATEGORY_NAME,''))
IF NOT EXISTS(SELECT [Name] FROM [AZUREDATABASE].[sds-pos-storiveo-db].dbo.ProductCategories WHERE [Name] = #SUBCATEGORY_NAME)
BEGIN
INSERT INTO [AZUREDATABASE].[sds-pos-storiveo-db].dbo.ProductCategories([Name],CreationTime,Inactive,ParentId,TenantId) VALUES(#SUBCATEGORY_NAME,#CreationTime,#CategoryStatus,#ParentId,#TenantId)
SELECT #CategoryId = ##IDENTITY
END
ELSE
BEGIN
SELECT #CategoryId = Id FROM [AZUREDATABASE].[sds-pos-storiveo-db].dbo.ProductCategories WHERE [Name] = #SUBCATEGORY_NAME
END
END
--Insert Product Brand Table
DECLARE #BrandId INT
--DECLARE #DefaultBrandId INT
--SET #DefaultBrandId = 1
IF ISNULL(#BRAND_NAME,'') <>''
BEGIN
--IF NOT EXISTS(SELECT BrandName FROM ProductBrands WHERE ISNULL(BrandName,'') = ISNULL(#BRAND_NAME,''))
IF NOT EXISTS(SELECT BrandName FROM [AZUREDATABASE].[sds-pos-storiveo-db].dbo.ProductBrands WHERE BrandName = #BRAND_NAME)
BEGIN
INSERT INTO [AZUREDATABASE].[sds-pos-storiveo-db].dbo.ProductBrands(BrandName,ManufacturerName,CreationTime,Inactive) VALUES(#BRAND_NAME,#BrandManfacturerName,#CreationTime,#BrandMasterStatus)
SELECT #BrandId = ##IDENTITY
END
ELSE
BEGIN
SELECT #BrandId = Id FROM [AZUREDATABASE].[sds-pos-storiveo-db].dbo.ProductBrands WHERE BrandName = #BRAND_NAME
END
END
--ELSE
--BEGIN
-- SET #BrandId = #DefaultBrandId
--END
--Insert Tax Table Records
DECLARE #TaxId INT
IF ISNULL(#TAX_CODE,'') <>''
BEGIN
IF NOT EXISTS(SELECT Code FROM [AZUREDATABASE].[sds-pos-storiveo-db].dbo.Taxes WHERE Code = #TAX_CODE)
BEGIN
INSERT INTO [AZUREDATABASE].[sds-pos-storiveo-db].dbo.Taxes(Code,Inactive,IsInclusive,[Name],TaxTypeId,TenantId) VALUES(#TAX_CODE,1,#TaxInclusive,#TaxName,1,#TenantId)
SELECT #TaxId = ##IDENTITY
INSERT INTO [AZUREDATABASE].[sds-pos-storiveo-db].dbo.TaxSchedules([Percentage],StartDateTime,TaxId) VALUES(#TAX_PERCENTAGE,#TaxStartDateTime,#TaxId)
END
ELSE
BEGIN
SELECT #TaxId = Id FROM [AZUREDATABASE].[sds-pos-storiveo-db].dbo.Taxes WHERE Code = #TAX_CODE
END
END
--Insert Product Table Records
DECLARE #ProductId INT
IF ISNULL(#PRODUCT_NAME,'') <>''
BEGIN
IF (#BUSINESS_TYPE = 'NF')
BEGIN
INSERT INTO [AZUREDATABASE].[sds-pos-storiveo-db].dbo.Products([Name],Inactive,IsReturnable,PrintName,
ProductBrandId,ProductCategoryId,TaxId,TenantId,CreationTime)
VALUES(#PRODUCT_NAME,#ProductStatus,#ProductIsReturnable,#PRINT_ON_RECEIPT,#BrandId,#CategoryId,#TaxId,#TenantId,#CreationTime)
END
ELSE
BEGIN
INSERT INTO [AZUREDATABASE].[sds-pos-storiveo-db].dbo.FuelProducts([Name],Inactive,PrintName,
ProductCategoryId,TaxId,TenantId,CreationTime)
VALUES(#PRODUCT_NAME,#ProductStatus,#PRINT_ON_RECEIPT,#CategoryId,#TaxId,#TenantId,#CreationTime)
END
SELECT #ProductId = ##IDENTITY
END
--Insert Product Barcode Records
IF ISNULL(#BAR_CODE_NO,'') <>''
BEGIN
IF (#BUSINESS_TYPE = 'NF')
BEGIN
INSERT INTO [AZUREDATABASE].[sds-pos-storiveo-db].dbo.ProductBarcodes(Barcode,Inactive,ProductId)VALUES(#BAR_CODE_NO,#ProductStatus,#ProductId)
END
END
FETCH NEXT FROM Product_Cursor
INTO #SUBCATEGORY_NAME,#CategoryStatus,#BRAND_NAME, #BrandMasterStatus, #BrandManfacturerName, #PRODUCT_NAME, #ProductStatus, #ProductIsReturnable,
#PRINT_ON_RECEIPT, #TenantId, #CreationTime, #ParentId, #BAR_CODE_NO, #TAX_CODE, #TaxName, #TaxInclusive, #TAX_PERCENTAGE, #TaxStartDateTime,#BUSINESS_TYPE
END
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
-- any other logiing or cleanup
END CATCH
IF ##TranCount>0 -- Transaction still open, so must have succeeded. If rolled back, trancount would be 0
COMMIT TRANSACTION
CLOSE Product_Cursor;
DEALLOCATE Product_Cursor;

Related

Creating an Instead of insert Trigger SQL

I am a DBA with my company. I am trying to create trigger that will check any insert statement for duplicates first then if none allow the original insert. Not even sure this can be done. The insert statements may be written by various users so the statements will never be the same. All I have found so far is the check for duplicates but the insert statement is then hard coded in the trigger. My plan is also to check update as well, but it is not important right now.
Here is my current code.
ALTER TRIGGER [dbo].[BlockDuplicatesOnTable]
ON [dbo].[blockduplicates]
Instead of INSERT, Update
AS
BEGIN
SET NOCOUNT ON;
Declare #ProviderAcctNumber nvarchar(50)
Declare #Referredby int
Declare #Action as char(1)
Declare #Count as int
Set #Action = 'I'
Select #Count = Count(*) from DELETED
IF #Count > 0
Begin
Set #Action = 'D'
Select #Count = count(*) from INSERTED
IF #Count > 0
Set #Action = 'U'
IF #Action = 'I'
Begin
IF not exists (Select 1 from inserted as i
inner join dbo.blockduplicates as b
on i.ProviderAcctNumber = b.ProviderAcctNumber
and i.Referredby = b.Referredby)
Begin
--execute original insert
End
Else
Begin
Print 'Duplicate insert'
Raiserror ('Duplicate Entry for Insert',16,1);
Return
End
End
Else IF #Action = 'U'
Begin
Select #ProviderAcctNumber = ProviderAcctNumber, #Referredby = Referredby from inserted
IF Not exists (Select 1 from deleted where ProviderAcctNumber = #ProviderAcctNumber and Referredby = #Referredby)
Begin
Print 'Update Statement is True';
End
Else
Begin
Print 'duplicate'
Raiserror ('Duplicate Entry for Update',16,1);
Return
End
End
End
End;

Azure SQL Database trigger is not running and I cannot seem to figure out why

I'm trying to update the status column of a table when the table has been edited. I use a similar trigger on another table to update this status but when I try to put the trigger on the table itself it will not run.
ALTER TRIGGER dbo.tr_Invoice_SetInvoiceStatus_Update
ON dbo.Invoice
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #InvoiceID int
DECLARE #TotalInvoice DECIMAL(18,2)
DECLARE #TotalPayments DECIMAL(18,2)
DECLARE #InvoiceStatus NVARCHAR(50)
DECLARE #InvoiceStatusID INT
SELECT #InvoiceID = ID
FROM Inserted i
SELECT #TotalPayments = IsNull(Sum(ph.Amount), 0)
FROM PaymentHistory ph
WHERE InvoiceID = #InvoiceID
SELECT #TotalInvoice = ISNULL(Total, 0)
FROM Invoice
WHERE ID = #InvoiceID
IF (#TotalPayments > 0)
BEGIN
IF (#TotalPayments >= #TotalInvoice)
BEGIN
SELECT #InvoiceStatus = 'Paid'
END
ELSE
BEGIN
SELECT #InvoiceStatus = 'Partially Paid'
END
END
ELSE
BEGIN
SELECT #InvoiceStatus = 'Open'
END
SELECT #InvoiceStatusID = ID
FROM dbo.InvoiceStatus
WHERE [Name] = #InvoiceStatus
UPDATE dbo.Invoice
SET InvoiceStatusID = #InvoiceStatusID
WHERE ID = #InvoiceID
END
GO
Any help would be great?

SQL DB script performance tuning

I need to fix a prod DB issue and the clean up script I've is taking really long. I tried couple of things without any luck, following is the script:
DECLARE #ErrorMessage NVARCHAR(4000)
DECLARE #ErrorSeverity INT
DECLARE #ErrorState INT
DECLARE #ErrorProcedure NVARCHAR(50)
BEGIN TRY
IF OBJECT_ID('tempdb..#SuspectData') IS NOT NULL
BEGIN
DROP TABLE #SuspectData
END
CREATE TABLE #SuspectData
(
IID INT,
CID INT,
PID INT
)
INSERT INTO dbo.#SuspectData
SELECT DL.IID,DL.CID,IT.PID FROM DL
INNER JOIN IT ON IT.CID = DL.CID AND IT.IID = DL.IID
WHERE DL.Suspect = 1
WHILE (1 = 1)
BEGIN
BEGIN TRANSACTION
UPDATE TOP (5000) TDS
SET TDS.DTID = 4
FROM
TDS
INNER JOIN dbo.#SuspectData SD
ON TDS.IID = SD.IID AND TDS.PID = SD.PID
WHERE TDS.DTID <> 4
IF ##ROWCOUNT = 0
BEGIN
COMMIT TRANSACTION
BREAK
END
COMMIT TRANSACTION
END
WHILE (1 = 1)
BEGIN
BEGIN TRANSACTION
UPDATE TOP (5000) TDA
SET TDA.DTID = 4
FROM
TDA
INNER JOIN dbo.#SuspectData SD
ON TDA.IID = SD.IID AND TDA.PID = SD.PID
WHERE TDA.DTID <> 4
IF ##ROWCOUNT = 0
BEGIN
COMMIT TRANSACTION
BREAK
END
COMMIT TRANSACTION
END
DROP TABLE #SuspectData
END TRY
BEGIN CATCH
SELECT #ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE(),
#ErrorProcedure = ERROR_PROCEDURE()
RAISERROR (#ErrorMessage,#ErrorSeverity,#ErrorState,#ErrorProcedure) ;
END CATCH
I also have following script to update everything at same time but it is also taking really long time like 24 hours or something.
DECLARE #ErrorMessage NVARCHAR(4000)
DECLARE #ErrorSeverity INT
DECLARE #ErrorState INT
DECLARE #ErrorProcedure NVARCHAR(50)
BEGIN TRY
IF OBJECT_ID('tempdb..#SuspectData') IS NOT NULL
BEGIN
DROP TABLE #SuspectData
END
CREATE TABLE #SuspectData
(
IID INT,
CID INT,
PID INT
)
INSERT INTO dbo.#SuspectData
SELECT DL.IID,DL.CID,IT.PID FROM DL
INNER JOIN IT ON IT.CID = DL.CID AND IT.IID = DL.IID
WHERE DL.Suspect = 1
BEGIN TRANSACTION
--Update about 1.5M records
UPDATE TDS
SET TDS.DTID = 4
FROM
TDS
INNER JOIN dbo.#SuspectData SD
ON TDS.IID = SD.IID AND TDS.PID = SD.PID
WHERE TDS.DTID <> 4
COMMIT TRANSACTION
BEGIN TRANSACTION
--Update about 4.5M records
UPDATE TDA
SET TDA.DTID = 4
FROM
TDA
INNER JOIN dbo.#SuspectData SD
ON TDA.IID = SD.IID AND TDA.PID = SD.PID
WHERE TDA.DTID <> 4
COMMIT TRANSACTION
DROP TABLE #SuspectData
END TRY
BEGIN CATCH
SELECT #ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE(),
#ErrorProcedure = ERROR_PROCEDURE()
RAISERROR (#ErrorMessage,#ErrorSeverity,#ErrorState,#ErrorProcedure) ;
END CATCH
I'm guessing that TDS table is large. In that case you can speed up join operation between your temp table and TDS (ON TDS.IID = SD.IID AND TDS.PID = SD.PID) by creating index on your temporary table:
either primary clustered:
CREATE TABLE #SuspectData
(
IID INT,
CID INT,
PID INT,
CONSTRAINT pk_temp PRIMARY KEY(IID, PID)
)
or not-clustered (if IID-PID pairs are not unique):
CREATE INDEX IDX_Temp_SuspectData ON #SuspectData(IID,PID)
What you can also do is check execution plan of those queries - it will help you locate which operation takes so long.
On the side: I'm generally against using cursors if you can avoid it.
First, is there anything that changes DL.Suspect = 1 to something else? or does your data set just keep getting bigger?
I also agree with Sean Lange, does the update have to be all or nothing?
I would recommend using a cursor. cursors are a great way to break up large transaction to speed up use and reduce table locks.
DECLARE db_cursor CURSOR FOR SELECT DL.IID,DL.CID,IT.PID FROM DL
INNER JOIN IT ON IT.CID = DL.CID AND IT.IID = DL.IID
WHERE DL.Suspect = 1;
DECLARE #first INT;
DECLARE #second INT;
DECLARE #third INT;
OPEN db_cursor;
FETCH NEXT FROM db_cursor INTO #first , #second , #third ;
WHILE ##FETCH_STATUS = 0
BEGIN
-- Do your updates one row at a time here
UPDATE TDS
SET TDS.DTID = 4
FROM TDS
WHERE TDS.IID = #first AND TDS.PID = #third
WHERE TDS.DTID <> 4
END;
CLOSE db_cursor;
DEALLOCATE db_cursor;

Stored Procedure Error - Transaction Count mismatch

I've been doing this stored procedure, however when I execute the stored procedure, I get an infinity execution. This cause a deadlock.
This is the error I got, can someone please help me on this?? Thanks.
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 2.
Code:
ALTER PROCEDURE [dbo].[spMaterialReceivingCreateItemRequirements]
#DomainSite nvarchar(8),
#ItemNo nvarchar(18),
#tReceiving_id integer,
#SampleRequired integer,
#UserName nvarchar(50)
AS
BEGIN
Declare #ErrorNo integer = '',
#New_JobNo integer,
#Status nvarchar(50) = 'InProcess',
#SPName nvarchar(max) = '',
#intSampleNo integer =1,
#ErrorMessage nvarchar(max) = ''
begin transaction t1
Begin try
BEGIN
--Generate 1 sample for item requirements
set #SampleRequired = 1
WHILE (#intSampleNo <= #SampleRequired)
BEGIN
insert into tItemRequirements
select
domainSite, #tReceiving_id, #ItemNo,
WorkCenter, tStationsType_id,
tSpecTestParameters_descriptions_id,
--row_number() OVER (ORDER BY ID) AS CurrentSet,
1 AS CurrentSet,
#intSampleNo, 1, 'InComplete', getdate(), #UserName
from
tspectestparameters
where
itemno = #ItemNo
set #intSampleNo = #intSampleNo +1
end
END
END TRY
Begin catch
SELECT
#ErrorNo = ERROR_NUMBER(),
#SPName = ERROR_PROCEDURE(),
#ErrorMessage = ERROR_MESSAGE();
rollback transaction t1
end catch
END
BEGIN TRANSACTION t1
BEGIN TRY
BEGIN
--Generate 1 sample for item requirements
SET #SampleRequired = 1
WHILE (#intSampleNo <= #SampleRequired)
BEGIN
INSERT INTO tItemRequirements
SELECT domainSite
, #tReceiving_id
, #ItemNo
, WorkCenter
, tStationsType_id
, tSpecTestParameters_descriptions_id
,
--row_number() OVER (ORDER BY ID) AS CurrentSet,
1 AS CurrentSet
, #intSampleNo
, 1
, 'InComplete'
, getdate()
, #UserName
FROM tspectestparameters
WHERE itemno = #ItemNo
SET #intSampleNo = #intSampleNo + 1
END
END
COMMIT
END TRY
BEGIN CATCH
SELECT #ErrorNo = ERROR_NUMBER()
, #SPName = ERROR_PROCEDURE()
, #ErrorMessage = ERROR_MESSAGE();
ROLLBACK TRANSACTION t1
END CATCH

Merge sql with date condition

I have create merge stored procedures as below, what i am trying to achieve is the following scenario:
Merge the new record if ProductTRN is not exist in ProductList table (complete)
Only Update the ProductList record in where the PU.CreateDate is bigger than CreateDate of target table which is ProductList (Not Complete)
Please advise me how I can achieve the second scenario above, thank you
CREATE PROCEDURE [dbo].[usp_ProductList_Merge]
AS
BEGIN
DECLARE #retValue INT
BEGIN TRY
IF OBJECT_ID('ProductList') IS NOT NULL
BEGIN
BEGIN TRANSACTION MergeConsumerTable
SET NOCOUNT ON;
MERGE dbo.ProductList AS target
USING
( SELECT
PU.ProductTRN,
PU.ProductName,
PU.ProductDescription,
PU.CreateDate
FROM dbo.TmpProductList PU
WHERE PU.ProductTRN = ProductTRN
) AS source (
ProductTRN,
ProductName,
ProductDescription
CreateDate)
ON ( (target.ProductTRN) = LOWER(source.ProductTRN)
)
WHEN MATCHED
THEN
UPDATE SET
ProductTRN= source.ProductTRN
WHEN NOT MATCHED
THEN
INSERT (
ProductTRN,
ProductName,
ProductDescription,
CreateDate
) VALUES
(
source.ProductTRN,
source.ProductName,
source.ProductDescription,
source.CreateDate,
);
DELETE PU
FROM dbo.TmpProductList PU
COMMIT TRANSACTION MergeProductListTable
SET #retValue = 1
SELECT #retValue
END
ELSE
BEGIN
SET #retValue = -1
SELECT #retValue
END
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION MergeProductListTable
DECLARE #ErrorMsg VARCHAR(MAX);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
SET #ErrorMsg = ERROR_MESSAGE();
SET #ErrorSeverity = ERROR_SEVERITY();
SET #ErrorState = ERROR_STATE();
SET #retValue = 0
SELECT #retValue
-- SELECT 0 AS isSuccess
END CATCH
END
WITH Source AS (
SELECT ProductTRN
,ProductName
,ProductDescription
,CreateDate
FROM dbo.TmpProductList
)
MERGE ProductList AS Target
USING Source
ON Target.ProductTRN = Source.ProductTRN
WHEN MATCHED
AND Source.CreatedDate > Target.CreatedDate
THEN UPDATE SET
ProductName = Source.ProductName
,ProductDescription = Source.ProductDescription
,CreateDate = Source.CreatedDate
WHEN NOT MATCHED BY TARGET
THEN INSERT (
ProductTRN
,ProductName
,ProductDescription
,CreateDate
)
VALUES (
Source.ProductTRN
,Source.ProductName
,Source.ProductDescription
,Source.CreatedDate
)