T SQL if column exists then (if it has value X then ( - sql-server

I need to perform the following logical clause:
If column is present and it has certain value then do something.
If not, then do something else.
IF EXISTS(
SELECT *
FROM sys.columns
WHERE Name = N'legacyoptions'
AND Object_ID = Object_ID(N'config '))
BEGIN
if ( select legacyoptions from config)=1
begin
Do stuff when legacy=1
end
else begin
Do stuff when legacy !=1
END
else
begin
do stuff when legacy is not present
end
However, this does not work in case legacyoptions is not present

Here is the way using TRY CATCH block and a dynamic SQL so this block of code will be compiled without table config and/or legacyoptionsfield in the database.
BEGIN TRY
DECLARE #legacyoptions int;
EXECUTE sp_executesql N'select TOP 1 #legacyoptions=legacyoptions from config',
N'#legacyoptions int OUTPUT',
#legacyoptions OUTPUT;
if #legacyoptions=1
begin
-- Do stuff when legacy=1
end
ELSE
BEGIN
-- Do stuff when legacy !=1
END
END TRY
BEGIN CATCH
-- do stuff when legacy is not present
END CATCH

try this :(i guess you are leaving an end of if)
IF EXISTS(
SELECT *
FROM sys.columns
WHERE Name = N'legacyoptions'
AND Object_ID = Object_ID(N'config '))
BEGIN
if ( select legacyoptions from config)=1
begin
Do stuff when legacy=1
end
else begin
Do stuff when legacy !=1
END
end
else
begin
do stuff when legacy is not present
end

This works, but seems stupid to me.
IF EXISTS( SELECT * FROM sys.columns WHERE Name = N'legacyoptions' AND Object_ID = Object_ID(N'config '))
BEGIN
exec('
if (select legacyoptions from config)=1
begin
print ''Config==1''
end
else
begin
print ''Config!=1''
end
')
end
else
begin
print 'no legacy'
end

Related

SQL ELSE block still throws error when IF condition is true

I have the following T-SQL script that copies the value of an old column into a new one, then drops the old column. See here:
--step 1: create new column
IF NOT EXISTS(SELECT 1 from sys.columns
WHERE Name = N'UserColumn2'
AND Object_ID = Object_ID(N'Account'))
BEGIN
ALTER TABLE Account
ADD UserColumn2 int null
;
END
GO
;
--step 2: copy and drop
IF NOT EXISTS(SELECT 1 from sys.columns
WHERE Name = N'UserColumn1'
AND Object_ID = Object_ID(N'Account'))
BEGIN
PRINT 'Column ''UserColumn1'' does not exist.';
END
ELSE
BEGIN
UPDATE Account
SET UserColumn2 = UserColumn1
WHERE UserColumn1 is not null
;
BEGIN TRY
Declare #count int;
SELECT #count = Count(AccountID)
FROM Account
WHERE UserColumn2 <> UserColumn1
;
IF #count > 0
BEGIN
--PRINT 'Not all records were properly updated. UserColumn1 has not been dropped.';
THROW 50000,'Not all records were properly updated. UserColumn1 has not been dropped.',1
;
END
ELSE
BEGIN
ALTER TABLE Account
DROP Column UserColumn1
;
END
END TRY
BEGIN CATCH THROW; END CATCH
END
GO
;
The first step runs correctly but the second step still throws an error in the ELSE block even if the UserColumn1 column doesn't exist:
(note: this actually throws on line 24 for the code here. The code in my SSMS doesn't have the comments for 'step 1', etc.)
Why is this happening and how can I prevent it?
I've tried removing the NOT and moving the instructions out of the ELSE block but the behavior did not change. I've also tried writing the beginning of the second step like this:
IF (SELECT 1 from sys.columns
WHERE Name = N'UserColumn1'
AND Object_ID = Object_ID(N'Account')) <> null
and I get the same result.
The issue is that the entire sql text is parsed and compiled before it's executed, the error is being thrown at compile time.
You could workaround it by executing the update statement in its own process using dynamic sql - although there is nothing dynamic in this usage, it simply defers the compilation and execution of the update statement where it only happens in your else condition:
IF NOT EXISTS(SELECT 1 from sys.columns
WHERE Name = N'UserColumn1'
AND Object_ID = Object_ID(N'Account'))
BEGIN
PRINT 'Column ''UserColumn1'' does not exist.';
END
ELSE
BEGIN
EXEC sp_executesql N'
UPDATE Account
SET UserColumn2 = UserColumn1
WHERE UserColumn1 is not null;'
...
...

How to use if else in SQL Server stored procedure

Stored procedure:
CREATE PROCEDURE validate
#blockID VARCHAR(255)
AS
BEGIN
IF #blockID = (SELECT blockID FROM block WHERE blockID = #blockID)
PRINT 'exists'
IF #blockID != (SELECT blockID FROM block WHERE blockID = #blockID)
PRINT 'does not exist'
END
When input the wrong one blockID, the 2nd if conditions does not work.
You probably want to use EXISTS.
CREATE PROCEDURE validate
#blockID VARCHAR(255)
AS
BEGIN
IF EXISTS (SELECT blockID FROM block WHERE blockID = #blockID)
PRINT'exists'
ELSE
PRINT'not exists'
END

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.

Is it possible to create SQL SERVER Function using transaction

I have a simple script which basically do a lot of db operation. Now I have a requirement to upgrade the database for which I need to include a creation of function inside the same transaction.
BEGIN TRY --Start the Try Block..
BEGIN TRANSACTION -- Start the transaction..
-- HERE I need to add one function like
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[FuctionTest]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[FuctionTest]
GO
CREATE FUNCTION FuctionTest
(
#inputVal int
)
RETURNS int
AS
BEGIN
RETURN (Select Id from [dbo].[test] where Id=#inputVal)
END
UPDATE MyChecking SET Amount = Amount - #Amount
WHERE AccountNum = #AccountNum
UPDATE MySavings SET Amount = Amount + #Amount
WHERE AccountNum = #AccountNum
COMMIT TRAN -- Transaction Success!
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN --RollBack in case of Error
How will I get this job done? I don't want to use a separate script to create the function.
yes, use EXEC('...') like:
--list all functions named like '%test_function%', which will not find any
SELECT [name] FROM sys.objects WHERE [name] like '%test_function%'
--create a function named 'test_function1'
exec ('create function [dbo].[test_function1] (#x int) returns varchar(50) as BEGIN return convert(varchar(50),#x)+''!'' END')
begin transaction
--create a function 'test_function2', which will be rolled back
exec ('create function [dbo].[test_function2] (#x int) returns varchar(50) as BEGIN return convert(varchar(50),#x)+''!!!!'' END')
rollback
--show the functions named like '%test_function%'
--which will only find 'test_function1', since 'test_function2'
--was rolled back
SELECT [name] FROM sys.objects WHERE [name] like '%test_function%'
OUTPUT:
name
-----------------------
(0 row(s) affected)
name
-------------------------
test_function1
(1 row(s) affected)
EDIT to show a begin try block....
BEGIN TRY
--list all functions named like '%test_function%', which will not find any
SELECT [name] FROM sys.objects WHERE [name] like '%test_function%'
--create a function named 'test_function1'
exec ('create function [dbo].[test_function1] (#x int) returns varchar(50) as BEGIN return convert(varchar(50),#x)+''!'' END')
begin transaction
--create a function 'test_function2', which will be rolled back
exec ('create function [dbo].[test_function2] (#x int) returns varchar(50) as BEGIN return convert(varchar(50),#x)+''!!!!'' END')
RAISERROR('force catch!',16,1) --send control to the BEGIN CATCH block
--should never get here
COMMIT
END TRY
BEGIN CATCH
IF XACT_STATE()!=0
BEGIN
ROLLBACK TRANSACTION
END
PRINT CASE WHEN ERROR_NUMBER() IS NOT NULL THEN 'Msg '+CONVERT(varchar(30),ERROR_NUMBER()) ELSE '' END+CASE WHEN ERROR_SEVERITY() IS NOT NULL THEN ', Level '+CONVERT(varchar(30),ERROR_SEVERITY()) ELSE '' END+CASE WHEN ERROR_STATE() IS NOT NULL THEN ', State '+CONVERT(varchar(30),ERROR_STATE()) ELSE '' END+CASE WHEN ERROR_PROCEDURE() IS NOT NULL THEN ', Procedure '+ERROR_PROCEDURE() ELSE '' END+CASE WHEN ERROR_LINE() IS NOT NULL THEN ', Line '+CONVERT(varchar(30),ERROR_LINE()) ELSE '' END+CASE WHEN ERROR_MESSAGE() IS NOT NULL THEN ', '+ERROR_MESSAGE() ELSE '' END
END CATCH
--show the functions named like '%test_function%'
--which will only find 'test_function1', since 'test_function2'
--was rolled back
SELECT [name] FROM sys.objects WHERE [name] like '%test_function%'
OUTPUT:
name
---------------------------------------------------
(0 row(s) affected)
Msg 50000, Level 16, State 1, Line 14, force catch!
name
---------------------------------------------------
test_function1
(1 row(s) affected)

Case statement in SQL Server 2005

I am not sure what to use in this scenario, but I think a Case statement is apt.
I do not know the syntax however. Can someone please guide me?
I have a variable called #Action which can have about 30 different values.
I want to do something like this
CASE
WHEN #Action = 'InsertTbl1' THEN
BEGIN
-- Some Insert statements and one update statements
END
WHEN #Action = 'RecalculateCol3' THEN
BEGIN
-- Some update statements
END
WHEN #Action = 'Closed' THEN
BEGIN
-- Some delete statements and some update statements
END
--- and so on.....
ELSE
BEGIN
END
END
Suggest a structure of IF and ELSE IF to mimic a switch.
IF #MyVar = 'Foo'
BEGIN
--react to Foo
END
ELSE IF #MyVar = 'Bar'
BEGIN
--react to Bar
END
ELSE
BEGIN
--default case.
END
Yes, you can use Else If. For example:
declare #temp int
set #temp = 3
if #temp = 1
print '1'
else if #temp > 1 and #temp < 3
print '2'
else if #temp >= 3
print '3'
I would still think about breaking it up into separate procedures as suggested by others

Resources