SQL Server if statement does not execute as expected - sql-server

I am trying to use the following stored procedure but there are some instances WHERE only the incremental happens AND the code does not run. What I need is that, when the program enters the IF statement, either it should run both the statements or None.
Stored procedure goes like this:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[spflpunch]
AS
BEGIN
DECLARE #id NUMERIC(18,0)
DECLARE #studname NVARCHAR(50)
DECLARE #punchtime DATETIME
DECLARE #samedaycount NUMERIC(2)
SELECT #id = (MAX(lastid)) FROM [smartswype].[dbo].[read]
PRINT #id
SELECT #studname = studname
FROM [SSWYPE_WEBDB].[dbo].[attdview]
WHERE id =#id
PRINT #studname
SELECT #punchtime = punchtime
FROM [SSWYPE_WEBDB].[dbo].[attdview]
WHERE id = #id
PRINT #punchtime
--SELECT #punchvarchar = CONVERT(VARCHAR(10),#punchtime, 103) + ' ' + CONVERT(VARCHAR(5), #punchtime, 14)
IF #id = (SELECT MAX(id) FROM [SSWYPE_WEBDB].[dbo].[attdview])
BEGIN
SELECT #samedaycount = COUNT(*)
FROM [SSWYPE_WEBDB].[dbo].[attdview]
WHERE (studname = #studname
AND CONVERT(DATE, punchtime) = CONVERT(DATE, #punchtime)) -- If firstpunch = 1 then it is the first punch
PRINT #samedaycount
IF #samedaycount =1
BEGIN
INSERT INTO [smartswype].[dbo].[firstlastpunch] ([studname], [DATE], [punch1], [punch2])
VALUES(#studname, CONVERT(DATE, #punchtime), #punchtime, NULL);
UPDATE [smartswype].[dbo].[read]
SET lastid = #id + 1;
END
ELSE IF (#samedaycount > 1)
BEGIN
UPDATE [smartswype].[dbo].[firstlastpunch]
SET punch2 = #punchtime
WHERE (studname = #studname AND DATE = CONVERT(DATE, #punchtime));
UPDATE [smartswype].[dbo].[read]
SET lastid = #id + 1;
END
END
END

If you want to ensure that both or none of the statements run, you should wrap the contents of the if statement in a transaction.
By wrapping it in a transaction, you can ensure that if one statement fails, that the other statement will not run.
Here is a link to the docs on transactions in SQL Server
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/commit-transaction-transact-sql

Related

insert data into sql table and get recent inserted iD and insert data in same table from different table

Here is the situation that I have to insert profile photos in the SQL table. But here are 2 scenarios the condition
if user is inserting photo and data from front end. Its working perfectly fine.
if user is skip the photo and just inserting his biography then in that case the default image should be inserted by default. I tried to do in front end Just adding dummy image in if else condition, but in DMZ server for some reason this is creating problem, on local server its working good.
Here is the Query...
ALTER PROCEDURE [dbo].[SavePhysicianBiodata]
-- Add the parameters for the stored procedure here
#ID int,
#Physician_Bio nvarchar(MAX),
#Physician_Mnemonic nvarchar(MAX),
#Physician_Image image,
#Physician_ImageType nvarchar(MAX),
#Physician_ImageFileName nvarchar(MAX)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
if( #ID is null OR #ID='')
begin
--if not image then deafult image will be applied
if((#Physician_ImageType is null or #Physician_ImageType='') and
(#Physician_ImageFileName is null or #Physician_ImageFileName='') )
begin
insert into Physician_Biodata(Physician_Bio, Physician_Mnemonic)
values(#Physician_Bio, #Physician_Mnemonic)
set #ID = SCOPE_IDENTITY()
update [dbo].[Physician_Biodata]
set Physician_Image=#Physician_Image,
Physician_ImageType=#Physician_ImageType,
Physician_ImageFileName=#Physician_ImageFileName
where ID=#ID
end
else
begin
-- Insert statements for procedure here when user adds photo as well
insert into Physician_Biodata(Physician_Bio, Physician_Mnemonic,
Physician_Image, Physician_ImageType, Physician_ImageFileName)
values(#Physician_Bio, #Physician_Mnemonic,
#Physician_Image,#Physician_ImageType,#Physician_ImageFileName)
end
end
else
begin
update [dbo].[Physician_Biodata]
set Physician_Bio=#Physician_Bio,
Physician_Mnemonic=#Physician_Mnemonic,
Physician_Image=#Physician_Image,
Physician_ImageType=#Physician_ImageType,
Physician_ImageFileName=#Physician_ImageFileName
where ID=#ID
end
END
In this query I also tried insert query which is given below
insert into Physician_Biodata(ID, Physician_Image, Physician_ImageType, Physician_ImageFileName)
select #ID, dd.Physician_Image,dd.Physician_ImageType,dd.Physician_ImageFileName from DefaultImage as dd
join Physician_Biodata
on Physician_Biodata.Physician_ImageFileName = dd.Physician_ImageFileName
where Physician_Biodata.ID = #ID
but getting error during execute procedure
Msg 544, Level 16, State 1, Procedure dbo.SavePhysicianBiodata, Line 35 [Batch Start Line 2]
Cannot insert explicit value for identity column in table 'Physician_Biodata' when IDENTITY_INSERT is set to OFF.
If somebody can help me it would be great.. Thanks in advance.
Yes I have already changed the first insert statement (removed ID) and
updated the 2nd query
set #ID = IDENT_CURRENT('Physician_Biodata')
update Physician_Biodata
set Physician_Biodata.Physician_Image= DefaultImage.Physician_Image, Physician_Biodata.Physician_ImageType= DefaultImage.Physician_ImageType, Physician_Biodata.Physician_ImageFileName=DefaultImage.Physician_ImageFileName from Physician_Biodata, DefaultImage where Physician_Biodata.ID=#ID
and it worked
It appears that Physician_Biodata's ID column is an IDENTITY, hence the exception you have.
Changing this...
INSERT INTO Physician_Biodata (
ID, Physician_Image, Physician_ImageType, Physician_ImageFileName
)
SELECT
#ID,
dd.Physician_Image,
dd.Physician_ImageType,
dd.Physician_ImageFileName
FROM DefaultImage AS dd
JOIN Physician_Biodata
ON Physician_Biodata.Physician_ImageFileName = dd.Physician_ImageFileName
WHERE
Physician_Biodata.ID = #ID;
To this...
INSERT INTO Physician_Biodata (
Physician_Image, Physician_ImageType, Physician_ImageFileName
)
SELECT
dd.Physician_Image,
dd.Physician_ImageType,
dd.Physician_ImageFileName
FROM DefaultImage AS dd
JOIN Physician_Biodata
ON Physician_Biodata.Physician_ImageFileName = dd.Physician_ImageFileName
WHERE
Physician_Biodata.ID = #ID;
Will make your "explicit value" exception go away as in your INSERT you are attempting to insert #ID into ID which is an identity column. You also use ID = #ID in your WHERE clause, which makes inserting #ID pointless as this would be a chicken-and-egg issue.
On another note, if #Physician_ImageType and #Physician_ImageFileName are both NULL going in, they'll still be NULL on your UPDATE given your existing SP's logic.
I've taken a little liberty to tidy/simplify your T-SQL and added a note about what I've questioned.
ALTER PROCEDURE [dbo].[SavePhysicianBiodata] (
#ID int,
#Physician_Bio nvarchar(MAX),
#Physician_Mnemonic nvarchar(MAX),
#Physician_Image image,
#Physician_ImageType nvarchar(MAX),
#Physician_ImageFileName nvarchar(MAX)
)
AS
BEGIN
SET NOCOUNT ON;
IF ISNULL( #ID, '' ) = ''
BEGIN
--if not image then deafult image will be applied
IF ISNULL( #Physician_ImageType, '' ) = '' AND ISNULL( #Physician_ImageFileName, '' ) = ''
BEGIN
INSERT INTO Physician_Biodata ( Physician_Bio, Physician_Mnemonic )
VALUES ( #Physician_Bio, #Physician_Mnemonic ) ;
SET #ID = SCOPE_IDENTITY();
/*
Where are you setting the values for #Physician_Image, #Physician_ImageType, and #Physician_ImageFileName? These are still NULL?
*/
UPDATE [dbo].[Physician_Biodata]
SET
Physician_Image = #Physician_Image,
Physician_ImageType = #Physician_ImageType,
Physician_ImageFileName = #Physician_ImageFileName
WHERE
ID = #ID;
END
ELSE BEGIN
-- Insert statements for procedure here when user adds photo as well
INSERT INTO Physician_Biodata (
Physician_Bio, Physician_Mnemonic, Physician_Image, Physician_ImageType, Physician_ImageFileName
)
VALUES (
#Physician_Bio, #Physician_Mnemonic, #Physician_Image, #Physician_ImageType, #Physician_ImageFileName
);
END
END
ELSE BEGIN
UPDATE [dbo].[Physician_Biodata]
SET
Physician_Bio = #Physician_Bio,
Physician_Mnemonic = #Physician_Mnemonic,
Physician_Image = #Physician_Image,
Physician_ImageType = #Physician_ImageType,
Physician_ImageFileName = #Physician_ImageFileName
WHERE
ID = #ID;
END
END

Insert Into SomeTable Exec StoredProcedure #Param1 = #param1, #Param2 = 'system' is not calling Stored Procedure

I have a scenario where I need to run a stored procedure individually as well as I need to call from some other stored procedure.
Let me present the scenario: I have 3 stored procedures in sequential call from another one. Like 1st stored procedure is getting called from the application when some raw financial data is being imported; 2nd stored procedure is getting called from 1st stored procedure and in 2nd stored procedure, there is a While loop in which my 3rd stored procedure is getting called.
I am posting here 2nd and 3rd stored procedure code here:
2ND stored procedure code:
If #loopCount > 0
Begin
While(#i <= #loopCount)
Begin
Select #RecoString = '',
#CompanyId = 0,
#UserId = 0
Select #RecoString = MainRecord,
#CompanyId = CompanyId,
#UserId = UsersId
From #RecoData With (Nolock)
Where Id = #i
Order By Id
/* 3rd stored procedure is getting called - IF NO INSERT Statement */
----Exec USP_Temp #IsReco = 1,#ReconcileBy = 'system',#UserCompanyId = #UserCompanyId,#UserId = #UserId,#finalCollection = #RecoString
/* 3rd stored procedure is NOT getting called - IF INSERT Statement */
Insert Into dbo.ReconcileInsertUpdateLog(TransferDetailId,Msg,ReconcilationId,IsFutureTransferReconciled)
Exec dbo.USP_Temp #IsReco = 1, #ReconcileBy = 'system', #CompanyId = #CompanyId, #UserId = #UserId, #finalCollection = #RecoString, #isAutoReconcile = 0
Set #i = #i + 1
End
End
3RD stored procedure code:
ALTER PROCEDURE dbo.USP_Temp
#IsReco Bit
,#ReconcileBy Nvarchar(250)
,#UserCompanyId int
,#UserId int
,#finalCollection Nvarchar(Max) = ''
,#isAutoReconcile Bit = 0
AS
BEGIN
Set Nocount On;
Declare #TransName Varchar(100)
Select #TransName = 'USP_Temp'
Begin Try
Begin Transaction #TransName
Declare #Msg Nvarchar(Max) = ''
,#ParentReconcilationId Int = 0 -- 07.25.2019
,#IsFutureTransferReconciled Int = 0 -- 07.25.2019
------------------------------------------------------------
-- Return result
------------------------------------------------------------
Insert Into dbo.TempReco(Comments)
Select 'Reached to USP_Temp 1 step ahead of Return final Result'
Select 1 As TransferDetailId
,#Msg As Msg
,#ParentReconcilationId As ReconcilationId -- 07.25.2019
,#IsFutureTransferReconciled As IsFutureTransferReconciled -- 07.25.2019
Commit Transaction #TransName
GoTo EndLevel
End Try
Begin Catch
Set #Msg = Error_Message()
GoTo Error
End Catch
Error:
BEGIN
Insert Into dbo.TempReco(Comments) Select 'Reached to USP_Temp - Error Block'
Rollback Transaction #TransName
Select 0 As TransferDetailId
,#Msg As Msg
,0 As ReconcilationId -- 07.25.2019
,0 As IsFutureTransferReconciled -- 07.25.2019
END
EndLevel:
END
GO
Look at the 2nd stored procedure code, I have commented the code which is working if no insert into statement prior to Exec SPName and when calling stored procedure along with insert into SomeTable prior statement then stored procedure is not getting called. Does anyone have some idea on this?

Using a SP to retrieve information or generate it if data exists in table

I have a requirement in which I need to run a select statement for data in a table if that data exists I need to return the values in a few of the columns. If the data doesn't exist, I need to insert a new row and return the inserted data.
I'll be using an API to execute the stored procedure and return the data, and then write that to a machine via OPC.
What I'm struggling with currently, is that a new entry is created, but does not increment the two columns I need to increment by a digit. In the code below, a new entry will create, but still returns and inputs the same value as the previous lot number. Is there a better way to achieve what I'm wanting to do?
CREATE PROCEDURE [dbo].[Lotconfirmation]
#plcid nvarchar(6) OUTPUT,
#supplierlot nvarchar(25),
#internallotnum nvarchar(25)OUTPUT,
#plclotnum nvarchar(25) OUTPUT,
#suppliercode nvarchar(1),
#supplierpartnum nvarchar(25),
#suppliermodel nvarchar(25),
#qtyconsumed int,
#id int OUTPUT,
#errormsg nvarchar(max) OUTPUT,
#errornum int OUTPUT,
#errorproc nvarchar(max) OUTPUT,
#errorstate int OUTPUT,
#errorline int OUTPUT
AS
BEGIN
BEGIN TRY
/* Check if lot already exists */
SELECT
#internallotnum = InternalLotNum, #plcid = PLCID,
#plclotnum = plclotnum, #id = id
FROM
dbo.ShrinkLotData
WHERE
SupplierMfgLot = #supplierlot
IF #internallotnum IS NULL
BEGIN
DECLARE #table TABLE
(
plcid nvarchar(6),
internallotnum nvarchar(25),
plclotnum nvarchar(25),
id int
)
INSERT INTO dbo.ShrinkLotData(PLCID, SupplierMfgLot, InternalLotNum, PLCLotNum, SupplierCode, SupplierPartNum, SupplierModel, QtyConsumed, Month, Day, Year, TimeStamp)
OUTPUT inserted.plcid, inserted.InternalLotNum, inserted.PLCLotNum, inserted.ID
VALUES (#plcid, #supplierlot,
(SELECT (MAX(InternalLotNum) + 1) FROM dbo.ShrinkLotData),
(SELECT MAX(RIGHT(InternalLotNum, 2) + 1) FROM dbo.ShrinkLotData),
#suppliercode, #supplierpartnum, #suppliermodel,
#qtyconsumed,
MONTH(GETDATE()), DAY(GETDATE()), YEAR(GETDATE()),
CURRENT_TIMESTAMP)
SELECT #plcid = plcid, #internallotnum = internallotnum, #plclotnum = plclotnum, #id = id
FROM #table
END
END TRY
/* E-mail if errors occurs */
BEGIN CATCH
SET #errormsg = 'SP Failed with msg:' + ERROR_MESSAGE()
SET #errornum = ERROR_NUMBER()
SET #errorproc = ERROR_PROCEDURE()
SET #errorstate = ERROR_STATE()
SET #errorline = ERROR_LINE()
/* Place holder to insert fail data into a table
INSERT INTO KSError (datestamp, errormsg, errorproc, errorstate, errorline)
VALUES (#datestamp, #errormsg, #errornum, #errorproc, #errorstate, #errorline)
*/
EXECUTE msdb.dbo.sp_send_dbmail
#recipients = 'email#domain.com',
#profile_name = 'Profile Alert',
#subject = 'KepServer Stored Procedure:',
#body = #errormsg
END CATCH
END
GO
EDIT:
It seems to be working when I cast values as an integer, so I'll need to review those data types and probably just set them up as integers.
(SELECT MAX(CAST(InternalLotNum AS INT)) + 1 FROM dbo.ShrinkLotData),
(SELECT MAX(RIGHT(CAST(InternalLotNum AS Int), 2) + 1) FROM dbo.ShrinkLotData),
While the question is still up, do you guys see a better / more efficient way to do what I'm hoping?
Thanks!
Your OUTPUT clause is returning the values directly to the client, instead of inserting them into your table variable. Should be something like:
INSERT INTO dbo.ShrinkLotData(PLCID, SupplierMfgLot, InternalLotNum, PLCLotNum, SupplierCode, SupplierPartNum, SupplierModel, QtyConsumed, Month, Day, Year, TimeStamp)
OUTPUT inserted.plcid, inserted.InternalLotNum, inserted.PLCLotNum, inserted.ID
INTO #table(plcid,InternalLotNum,PLCLotNum,ID)
VALUES (#plcid, #supplierlot,
(SELECT (MAX(InternalLotNum) + 1) FROM dbo.ShrinkLotData),
(SELECT MAX(RIGHT(InternalLotNum, 2) + 1) FROM dbo.ShrinkLotData),
#suppliercode, #supplierpartnum, #suppliermodel,
#qtyconsumed,
MONTH(GETDATE()), DAY(GETDATE()), YEAR(GETDATE()),
CURRENT_TIMESTAMP)
SELECT #plcid = plcid, #internallotnum = internallotnum, #plclotnum = plclotnum, #id = id
FROM #table

T - SQL statement IF EXIST SELECT and INSERT

How can I make this possible..really need advice? I want to get the id where my condition is met, then used it in my queries.
IF EXISTS (Select sn_id as snid FROM device.sn WHERE dname_id = 62 and sn_value = '123415')
BEGIN
SELECT MAX(id) AS maxid FROM device.list
INSERT INTO parts (sn_id,device_id) VALUES (snid, maxid)
END
ELSE
BEGIN
PRINT 'id does not exist'
return
END
You can use variables to store the results from the two queries and then use those values in your INSERT statement.
If you're using Microsoft SQL Server then the following may work (but there may be superficial syntax errors as it hasn't been tested). Note that I've assumed the type of your columns is int.
DECLARE #snid int
SET #snid = NULL
Select #snid = sn_id FROM device.sn WHERE dname_id = 62 and sn_value = '123415'
IF #snid IS NULL
BEGIN
PRINT 'id does not exist'
END
ELSE
BEGIN
DECLARE #maxid int
SELECT #maxid = MAX(id) AS maxid FROM device.list
INSERT INTO parts (sn_id,device_id) VALUES (#snid, #maxid)
END
In SQLServer. This script at first insert records and after checks count of the inserted rows
INSERT INTO parts (sn_id, device_id)
SELECT sn_id, (SELECT MAX(id) FROM device.list)
FROM device.sn
WHERE dname_id = 62 and sn_value = '123415'
IF ##ROWCOUNT = 0 PRINT 'id does not exist'
Declare #snid int=null
Declare #maxid int=1 -- if no value exists in device.list table
set #snid = (select sn_id from device.sn WHERE dname_id = 62 and sn_value = '123415')
set #maxid = (select MAX(id) AS maxid FROM device.list)
if #snid is not null
Begin
insert into parts(sn_id,device_id)
values(#snid,#maxid)
End
else
Begin
print 'ID does not exist'
End

Turn off implicit transactions

I would like to do a insert into using a select, but I know that some rows might fail (that is expected). Is there a way to change the implicit transactions of SQL Server 2008 off so that the ones that have not failed are not rolled back?
-- get the count of the customers to send the sms to
SELECT #count = COUNT(*)
FROM PreCampaignCustomer
WHERE Processed = 0 AND CampaignID = #campaignid
AND ErrorCount < 5
WHILE (#count > 0)
BEGIN
DECLARE #customerid INT,
#carrierid INT,
#merchantcustomerid INT,
#smsnumber NVARCHAR(50),
#couponcode NVARCHAR(20)
SELECT TOP 1 #customerid = pcc.CustomerID, #merchantcustomerid = pcc.MerchantCustomerID,
#carrierid = c.CarrierID, #smsnumber = c.SMSNumber
FROM PreCampaignCustomer pcc
INNER JOIN Customer c ON c.ID = pcc.CustomerID
WHERE pcc.Processed = 0 AND pcc.CampaignID = #campaignid
AND pcc.ErrorCount < 5
ORDER BY pcc.ErrorCount
--set the couponcode
IF #couponlength = -1
BEGIN
SET #couponcode = 'NOCOUPON'
END
ELSE
BEGIN
EXEC [GenerateCouponCode]
#length = 9,
#couponcode = #couponcode OUTPUT
END
BEGIN TRY
--use try/catch just in case the coupon code is repeated or any other error
--Set the coupon text
DECLARE #coupontext NVARCHAR(200),
#smsrequestxml XML
IF #coupontypecode = 1 --NONE
BEGIN
SET #coupontext = #merchantname + ': ' + #smsmessage + ', Use Code: ' + dbo.FormatCouponCode(#couponcode, #couponcodegrouping) + '. Reply STOP to quit'
END
ELSE
BEGIN
SET #coupontext = #merchantname + ': ' + #smsmessage + '. Reply STOP to quit'
END
EXEC GetSMSRequest #config = #smsconfig,
#smsType = 1, --Submit
#address = #smsnumber,
#carrierID = #carrierid,
#message = #coupontext,
#xml = #smsrequestxml OUTPUT
BEGIN TRAN
--create the CampaignCustomer record
INSERT INTO CampaignCustomer
(CampaignID, CustomerID, CouponCode, Active)
VALUES
(#campaignid, #customerid, #couponcode, 1)
--Add the record to the queue
INSERT INTO SMSQueue
(CarrierID, [Address], [Message], TimeToSend, RequestXML, QueueID, HTTPStatusCode, Retries)
VALUES
(#carrierid, #smsnumber, #coupontext, #timetosend, #smsrequestxml, #queueid, 0, 0)
--Create Outgoing SMS Log
INSERT INTO SMSOutgoingLog
(MerchantID, MerchantGroupID, MessageTypeCode, CreatedDate, Active)
VALUES
(#merchantid, #merchantgroupid, #messagetypecode, GETDATE(), 1)
--Update the LastSentSMSTime of the MerchantCustomer
UPDATE MerchantCustomer
SET LastSentSMS = GETDATE(),
ModifiedDate = GETDATE()
WHERE ID = #merchantcustomerid
UPDATE PreCampaignCustomer
SET Processed = 1,
ModifiedDate = GETDATE()
WHERE CustomerID = #customerid
AND CampaignID = #campaignid
COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN
-- Set the error
UPDATE PreCampaignCustomer
SET ErrorCount = ErrorCount + 1,
ModifiedDate = GETDATE(),
ErrorMessage = ERROR_MESSAGE(),
ErrorNumber = ERROR_NUMBER()
WHERE CustomerID = #customerid
AND CampaignID = #campaignid
END CATCH
SELECT #count = COUNT(*)
FROM PreCampaignCustomer
WHERE Processed = 0 AND CampaignID = #campaignid
AND ErrorCount < 5
END
no, the INSERT is a single command. Transactions control how multiple commands are combined together into single units of work, and not how rows are combined within a single command. You can't have some rows INSERT and the ones that fail (some constraint issue) and just be ignored. if any rows fail, then the entire INSERT fails.
why not try modifying the SELECT to exclude rows that will fail?
something like:
INSERT INTO YourTable
(col1, col2, col3)
SELECT
colA, colB, ColC
FROM YourOtherTable
WHERE ColA NOT IN (SELECT col1 FROM YourTable)
Thinking out of the box, if you use SSIS to do this, you can send your failed rows down a differnt path or just throw them out.
You're probably thinking about the IGNORE_DUP_KEY property of a unique index.
See this related SO question and the official MSDN article on IGNORE_DUP_KEY.
You'll have to either use ALTER INDEX to add this property, or (if the unique constraint is on the primary key) drop and re-create it.
Once this is in place, any inserts should only reject invalid rows instead of the entire batch.
It is possible to control behaviour of transansactions using SET XACT_ABORT OFF (ON) -- more here.

Resources