T - SQL statement IF EXIST SELECT and INSERT - sql-server

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

Related

How do I use WHILE loop in CASE statement in SQL

In 'CASE' statement in SQL we use a bool condition and get a TRUE or FALSE result. In this situation I have to use non-bool unlimited condition. But I can't...
ALTER proc [dbo].[sp_StudentList](#CreatedBy nvarchar(max))
as
begin
declare #LikedBy nvarchar(max) = (Select LikedBy from LikeStatus)
declare #TeacherRequestID int = (Select TeacherRequestID from LikeStatus where LikedBy=#CreatedBy)
declare #UserName nvarchar(max) = #CreatedBy
declare #i int = 1
declare #NumberOfRows int = (select count(*) from TeacherRequest)
select SP.StuThana, SP.StuDist, TR.StudentName,TR.StudentCode, TR.Class, TR.Subject, TR.StuGroup,TR.StuRelation, TR.Institute,TR.Status, TR.LikeStatus,
**CASE
WHEN
WHILE(#i <= #NumberOfRows)
BEGIN
#TeacherRequestID = TR.ID THEN 'Liked' Else 'Like'
set #i = #i + 1
END
END as LikeFlag**
from StudentsProfile SP join TeacherRequest TR on SP.CreatedBy=TR.CreatedBy
--sp_StudentList 'teacher1#gmail.com'
end
The technical answer to your question as posed in your title is that you can't.
declare #i int = 5;
select case when (while #i > 0 begin set #i = #i - 1 end) then 1 else 0 end;
-- Incorrect syntax near the keyword 'while'
Is your intention to just determine whether a student listed in a row likes the associated teacher? If so, then you're looking for whether an entry exists in another table, not how often it occurs. And I would tie it to sp.createdBy, not #createdBy.
select // ...,
likeFlag =
case when exists (
select 0
from likeStatus ls
where ls.likedBy = sp.createdBy
and ls.TeacherRequestId = tr.id
) then 'Liked'
else 'Like'
end
from studentsProfile sp
join teacherRequest tr on sp.createdBy = tr.createdBy
If for some reason you really only need 'Liked' based on #createdBy, then change ls.likedBy = sp.createdBy to ls.likedBy = #createdBy, but I don't see a strong use case for that.

IF NOT EXIST insert ELSE IF update ELSE IF EXISTS and is not Numeric DELETE From WHERE

I want to modify the Stored Procedure below.
#UserID INT
#Unlock VARCHAR(4)
AS
SET NOCOUNT ON
IF NOT EXISTS (SELECT * FROM dbo.tblUnlockCode WHERE iUserID = #UserID)
BEGIN
IF ISNUMERIC(#Unlock) = 1
BEGIN
INSERT dbo.tblUnlockCode (iUserID, sUnlockCode) VALUES (#UserID, #Unlock)
END
I would actually like to add to it, to where if the iUserID exists Update the #Unlock to the new Pin, and if the iUserID exists on the table but the #Unlock gets erased on the textfield(in access) it gets removed from the Table. I only want to store the iUserIDs that 4 digit pins. How could I do that?
P.S. on access I am checking if the pin is 4 digits.
Try this (I also recommend adding error handling if you have none):
#UserID INT
#Unlock VARCHAR(4)
AS
SET NOCOUNT ON
IF NOT EXISTS (SELECT * FROM dbo.tblUnlockCode WHERE iUserID = #UserID)
BEGIN
IF ISNUMERIC(#Unlock) = 1
BEGIN
INSERT dbo.tblUnlockCode (iUserID, sUnlockCode) VALUES (#UserID, #Unlock)
END
END
ELSE
BEGIN
IF ISNUMERIC(#Unlock) = 1
BEGIN
UPDATE dbo.tblUnlockCode set sUnlockCode=#Unlock WHERE iUserID= #UserID
END
ELSE --Assuming you want to clear the record if unlock code is empty
BEGIN
DELETE dbo.tblUnlockCode WHERE iUserID= #UserID
END
END

SQL Server if statement does not execute as expected

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

Efficient way of doing "insert only if node with specific value does not exist" for an xml column

Say, I have a xml column that looks like this:
<mi>
<m>42</m>
</mi>
Assuming table:
Word(WordId:bigint, Wordtext:nvarchar, MessageIndex:xml)
I do NOT want the following parameterized query to insert a new xml node if #MessageId already exists somewhere in the xml tree of Messageindex, but rather either fail with a deterministic error code, or silently:
begin try
insert into Word (WordText, MessageIndex) values (#WordText, '<mi></mi>');
update Word set MessageIndex.modify('insert (<m>{sql:variable(""#MessageId"")}</m>) into(/mi)[1]') where WordId = scope_identity();
end try
begin catch
if error_number() = 2627
begin
update Word set
MessageIndex.modify('insert (<m>{sql:variable(""#MessageId"")}</m>) into(/mi)[1]')
where
WordText = #WordText;
end
else
throw
end catch
select WordId from Word where WordText = #WordText;
How do I make this happen efficiently?
Something like this work for you?
DECLARE #Word TABLE (WordId bigint identity, Wordtext NVARCHAR(20), MessageIndex xml )
insert into #word ( messageIndex )
select '<mi>
<m>42</m>
</mi>'
DECLARE #WordText NVARCHAR(20) = 'wordText'
DECLARE #messageId INT = 42
begin try
if exists ( select 1 from #Word where MessageIndex.exist('//mi[.=sql:variable("#MessageId")]') = 0 )
begin
insert into #Word (WordText, MessageIndex) values (#WordText, '<mi></mi>');
update #Word set MessageIndex.modify('insert <m>{sql:variable("#MessageId")}</m> into (mi)[1]')
where WordId = scope_identity();
end
--else
-- do something here?
end try
begin catch
if error_number() = 2627
begin
update #Word set MessageIndex.modify('insert <m>{sql:variable("#MessageId")}</m> into (mi)[1]')
where WordText = #WordText;
end
else
throw
end catch
select * from #Word
This is an older post, but I'd to share my solution, which applies when an element either exists or not:
First, we need update when element (varchar type) exists:
UPDATE PD
SET
[ValuesXml].modify('replace value of
(/Employee/KeyValue/text())[1] with (sql:column("x.KeyValue"))')
FROM Pdetail PD
INNER JOIN TableXml x ON PD.PId = x.PId
WHERE PD.[ValuesXml].exist('/Employee/KeyValue') = 1
Second, we need insert when element does not exists:
UPDATE PD
SET
[ValuesXml].modify(
'insert <KeyValue>{sql:column("x.KeyValue")}</KeyValue> into (/Employee)[1]')
FROM RK.Pdetail PD
INNER JOIN TableXml x ON PD.PId = x.PId
WHERE PD.[ValuesXml].exist('/Employee/KeyValue') = 0
If you need work with multiple instances of entities in XML you'll need use CROSS APPLY and remove the [1] singleton indicator.

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