Sql if statement after another if check - sql

I'm working with Microsoft SQL Server.
IF EXISTS (
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'ServerSettings'
AND COLUMN_NAME = 'MapIsAlwayCalcLenByWebServices'
)
IF (
SELECT MapIsAlwayCalcLenByWebServices
FROM ServerSettings
) = 0
UPDATE ServerSettings
SET MapCalculateDistanceSource = 0
Does anybody know why this code throw the error "Invalid column name". I thought that second select execute only when the first if is true.

No, the entire batch is first compiled, and then execution starts. Since it can't compile the batch because you reference an invalid column, it never executes the if statement.
You would need to protect the code that references a possibly absent column in an EXEC, something like:
if exists(select * from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'ServerSettings' and
COLUMN_NAME = 'MapIsAlwayCalcLenByWebServices')
begin
exec('UPDATE ServerSettings SET MapCalculateDistanceSource = 0
WHERE MapIsAlwayCalcLenByWebServices = 0')
end

Try this one -
IF EXISTS(
SELECT 1
FROM sys.columns c
WHERE c.name = 'MapIsAlwayCalcLenByWebServices'
AND c.[object_id] = OBJECT_ID('dbo.ServerSettings')
) BEGIN
EXEC sys.sp_executesql '
UPDATE dbo.ServerSettings
SET MapCalculateDistanceSource = 0
WHERE MapIsAlwayCalcLenByWebServices = 0'
END

Another way to check the existing column
IF COL_LENGTH('dbo.ServerSettings', 'MapIsAlwayCalcLenByWebServices') IS NOT NULL
EXEC ('UPDATE dbo.ServerSettings
SET MapCalculateDistanceSource = 0
WHERE MapIsAlwayCalcLenByWebServices = 0')

Related

SQL Server: why variable works outside IF

I have trigger where on top of it I declare
DECALRE #variable VARCHAR(100) = ' '
And then below it, I have this sample IF statement
IF UPDATE ([data])
BEGIN
SET #variable = 'Data change'
END
And then insert with this #variable on the end of the trigger.
My problem is that even though [data] remains unchanged it inserts 'Data change' into DB instead of ''
Documentation of UPDATE - Trigger Functions states clearly:
UPDATE() returns TRUE regardless of whether an INSERT or UPDATE attempt is successful.
Please check:
UPDATE t SET id = 2 WHERE id = 1; /*if block is not executed */
-- 1 rows affected
and(even though there is no real change on data column):
UPDATE t SET id = 1, data = data WHERE id = 2; /*if block is executed */
-- Data change
-- 1 rows affected
db<>fiddle demo
As the others suggested, Update() is always true
So you may try a solution like the following
DECLARE #variable VARCHAR(100) = 'initial data'
if (Select Count(*)
From [<TblToBeUpdated>] t
INNER JOIN Inserted i ON t.[<PK>] = i.[<PK>]
INNER JOIN Inserted d ON t.[<PK>] = d.[<PK>]
WHERE t.[<ColToBeUpdated>] <> i.[<ColOfQuery>] OR
t.[<ColToBeUpdated>] <> d.[<ColOfQuery>]
) > 0
Begin
SET #variable = 'Data change'
End
see the fiddle

How to use SQL column name only if the column exists?

I've been trying to get a textual result from CASE(def.OPTION_CATEGORY_ID) in a select, but I'm having a hard time implementing the terms.
What I'm trying to do is to check if OPTION_CATEGORY_ID is an existing column in sys.columns. If it is then I'm trying to make the int to text translation using the When - Then on the bottom but the SQL is not aware of the column name so CASE(def.OPTION_CATEGORY_ID) is failing because the column name is invalid.
Is there any way to call def.OPTION_CATEGORY_ID using an alias name so the SQL won't fail it before hand?
Thanks
SELECT DISTINCT *
FROM
(SELECT def.OPTION_DEF_ID AS 'Def ID',
ass.ASSET_NAME AS 'Asset Name',
CASE(def.OPTION_TYPE_ID)
WHEN 1 THEN 'A'
WHEN 2 THEN 'B'
END AS 'Option Type',
case when exists (SELECT name
FROM sys.columns
WHERE Name = 'OPTION_CATEGORY_ID'
AND Object_ID = Object_ID(N'TFC_OPTION_DEFINITION'))
then
-- Column Exists
CASE(def.OPTION_CATEGORY_ID)
WHEN 1 THEN 'C'
WHEN 2 THEN 'D'
WHEN 3 THEN 'E'
WHEN 4 THEN 'F'
end
End AS 'test' ,
-- the rest of the select
If you want to select a column and you are not sure if it exists, you cannot write it explicitly in your code, and expect it to compile.
You should build the statement dynamically based on the run time information of which the column exists or not:
DECLARE #statement VARCHAR(MAX)
IF((SELECT COUNT(*)
FROM sys.columns
WHERE Name = 'OPTION_CATEGORY_ID'
AND Object_ID = Object_ID(N'TFC_OPTION_DEFINITION')) > 0)
BEGIN
SET #statement = --assign a query which uses OPTION_CATEGORY_ID
END
ELSE
BEGIN
SET #statement = --assign a query which does not use OPTION_CATEGORY_ID
END
EXEC sp_executesql #statement

SQL Server stored procedure/cursor

I have a list of 20 spatial tables (Zoom1-Zoom20) and from time invalid geometry pops up in these tables. When the invalid geometry occurs I run the following statement to find where the invalid geometry is:
SELECT ID FROM Zoom10 WhERE Location.STIsValid() = 0
Typically I have to run the above statement for every Zoom table (the error that leads to the invalid geometry does not indicate which zoom table has invalid geometry) and when a result is returned from the select statement I run the following statement to correct the geometry:
UPDATE MGeoZoom10 set Location = Location.MakeValid() where Location.STIsValid() = 0
My question is can this process be automated with a stored procedure that gets the list of zoom tables
select name from sys.tables where name like '%zoom'
and then loops through the zoom tables with
SELECT ID FROM Zoom10 WhERE Location.STIsValid() = 0
and if a result is returned it runs the update statement on the zoom table?
Try this:
sp_msforeachtable '
if ''?'' Like ''%Zoom%''
Begin
If Exists(SELECT ID FROM ? WhERE Location.STIsValid() = 0)
UPDATE ? set Location = Location.MakeValid() where Location.STIsValid() = 0
End
'
Do you have 2 UDFs called STIsValid and MakeValid? If so, you could do something like this...
SELECT id INTO #Processed FROM Sysobjects WHERE name = '(no such table)'
DECLARE #TableId int, #TableName varchar(255), #CorrectionSQL varchar(255)
SELECT #TableId = MIN(id) FROM Sysobjects WHERE type = 'U' AND name LIKE '%zoom'
AND id NOT IN (SELECT id FROM #Processed)
SET #TableId = ISNULL(#TableId, -1)
WHILE #TableId > -1 BEGIN
PRINT #TableId
SELECT #TableName = name FROM Sysobjects WHERE type = 'U' AND id = #TableId
SET #CorrectionSQL = 'UPDATE ' + #TableName + ' SET Location = dbo.MakeValid(Location) where dbo.STIsValid(Location) = 0'
PRINT #CorrectionSQL
EXEC(#CorrectionSQL)
INSERT INTO #Processed (id) VALUES(#TableId)
SELECT #TableId = MIN(id) FROM Sysobjects WHERE type = 'U' AND name IN ('DimAccount', 'DimCurrency', 'DimCustomer')
AND id NOT IN (SELECT id FROM #Processed)
END

SQL: How to use a column that was just added

I am trying to add 2 columns and then I would like to set some values to them but I get a compile-error saying the column does not exist. I am using the following script:
IF #LogProcessed = 0
Begin
IF NOT EXISTS (select column_name from INFORMATION_SCHEMA.columns where table_name = 'SYSTM_FRM' and column_name = 'SF_Ip_TXT')
ALTER TABLE SYSTM_FRM add SF_Ip_TXT NVARCHAR(20)
IF NOT EXISTS (select column_name from INFORMATION_SCHEMA.columns where table_name = 'SYSTM_FRM' and column_name = 'SF_Port_NUM')
ALTER TABLE SYSTM_FRM add SF_Port_NUM int
IF (EXISTS (select column_name from INFORMATION_SCHEMA.columns where table_name = 'FRM' and column_name = 'FRM_Ip_TXT') AND
EXISTS (select column_name from INFORMATION_SCHEMA.columns where table_name = 'FRM' and column_name = 'FRM_Ip_TXT'))
begin
Update dbo.SYSTM_FRM
SET dbo.SYSTM_FRM.SF_Ip_TXT = dbo.FRM.FRM_Ip_TXT,
dbo.SYSTM_FRM.SF_Port_NUM = dbo.FRM.FRM_Port_NUM
FROM dbo.FRM INNER JOIN dbo.SYSTM_FRM ON dbo.FRM.FRM_RCRD_NUM = dbo.SYSTM_FRM.SF_FrameRecord_NUM
ALTER TABLE FRM DROP COLUMN FRM_Ip_TXT
ALTER TABLE FRM DROP COLUMN FRM_Port_NUM
end
Update [Update_Log]
Set Update_Log_Processed = 1
Where [Update_Log_Version] = '00001'
end
Is there any way to use a column that I am adding in the same script?
you cannot save it in a proc like that
example
create table TestAdd2 (id int)
go
You cannot create this procedure
create proc prTest as
insert TestAdd2 values (1)
exec ('ALTER TABLE TestAdd2 add SF_Port_NUM int')
update TestAdd2 set id = 1,SF_Port_NUM = 2
select * from TestAdd2
GO
You get this error
Msg 207, Level 16, State 1, Procedure prTest, Line 7
Invalid column name 'SF_Port_NUM'.
This is because at parse time the column does not exist
However if you use dynamic SQL for the update you are good to go
create proc prTest2 as
insert TestAdd2 values (1)
exec ('ALTER TABLE TestAdd2 add SF_Port_NUM int')
exec ('update TestAdd2 set id = 1,SF_Port_NUM = 2')
select * from TestAdd2
GO
in your case your update statement would be
exec('Update dbo.SYSTM_FRM
SET dbo.SYSTM_FRM.SF_Ip_TXT = dbo.FRM.FRM_Ip_TXT,
dbo.SYSTM_FRM.SF_Port_NUM = dbo.FRM.FRM_Port_NUM
FROM dbo.FRM INNER JOIN dbo.SYSTM_FRM
ON dbo.FRM.FRM_RCRD_NUM = dbo.SYSTM_FRM.SF_FrameRecord_NUM')
Put a GO in between
All DDL statements should follow the statement seperator GO in order to make use of it

How do I query if a database schema exists

As part of our build process we run a database update script as we deploy code to 4 different environments. Further, since the same query will get added to until we drop a release into production it has to be able to run multiple times on a given database. Like this:
IF NOT EXISTS (SELECT * FROM sys.tables WHERE object_id = OBJECT_ID(N'[Table]'))
BEGIN
CREATE TABLE [Table]
(...)
END
Currently I have a create schema statement in the deployment/build script. Where do I query for the existence of a schema?
Are you looking for sys.schemas?
IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = 'jim')
BEGIN
EXEC('CREATE SCHEMA jim')
END
Note that the CREATE SCHEMA must be run in its own batch (per the answer below)
#bdukes is right on the money for determining if the schema exists, but the statement above won't work in SQL Server 2005. CREATE SCHEMA <name> needs to run in its own batch. A work around is to execute the CREATE SCHEMA statement in an exec.
Here is what I used in my build scripts:
IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = '<name>')
BEGIN
-- The schema must be run in its own batch!
EXEC( 'CREATE SCHEMA <name>' );
END
This is old so I feel compelled to add: For SQL SERVER 2008+ These all work (for the select part), then use EXECUTE('CREATE SCHEMA <name>') to actually create it on negative results.
DECLARE #schemaName sysname = 'myfunschema';
-- shortest
If EXISTS (SELECT 1 WHERE SCHEMA_ID(#schemaName) IS NOT NULL)
PRINT 'YEA'
ELSE
PRINT 'NOPE'
SELECT DB_NAME() AS dbname WHERE SCHEMA_ID(#schemaName) IS NOT NULL -- nothing returned if not there
IF NOT EXISTS ( SELECT top 1 *
FROM sys.schemas
WHERE name = #schemaName )
PRINT 'WOOPS MISSING'
ELSE
PRINT 'Has Schema'
SELECT SCHEMA_NAME(SCHEMA_ID(#schemaName)) AS SchemaName1 -- null if not there otherwise schema name returned
SELECT SCHEMA_ID(#schemaName) AS SchemaID1-- null if not there otherwise schema id returned
IF EXISTS (
SELECT sd.SchemaExists
FROM (
SELECT
CASE
WHEN SCHEMA_ID(#schemaName) IS NULL THEN 0
WHEN SCHEMA_ID(#schemaName) IS NOT NULL THEN 1
ELSE 0
END AS SchemaExists
) AS sd
WHERE sd.SchemaExists = 1
)
BEGIN
SELECT 'Got it';
END
ELSE
BEGIN
SELECT 'Schema Missing';
END
If the layout of components allows it, this works too.
IF EXISTS (SELECT 1 FROM sys.schemas WHERE name = 'myschema') SET NOEXEC ON
go
CREATE SCHEMA myschema
GO
SET NOEXEC OFF -- if any further processing is needed.
GO
Just to be extra "defensive", the following version generates a Type conversion error to account for the possibility (however unlikely) of > 1 matching Schema's similar to how validation code often intentionally Throw Exception's because I believe it's good to and I believe it's "'best practice'" to account for all possible return results however unlikely and even if it's just to generate a fatal exception because the known effects of stopping processing is usually better than unknown cascading effects of un-trapped errors. Because it's highly unlikely, I didn't think it's worth the trouble of a separate Count check + Throw or Try-Catch-Throw to generate a more user-friendly fatal error but still fatal error nonetheless.
SS 2005-:
declare #HasSchemaX bit
set #HasSchemaX = case (select count(1) from sys.schemas where lower(name) = lower('SchemaX')) when 1 then 1 when 0 then 0 else 'ERROR' end
SS 2008+:
declare #HasSchemaX bit = case (select count(1) from sys.schemas where lower(name) = lower('SchemaX')) when 1 then 1 when 0 then 0 else 'ERROR' end
Then:
if #HasSchemaX = 1
begin
...
end -- if #HasSchemaX = 1
IF NOT EXISTS (SELECT TOP (1) 1 FROM [sys].[schemas] WHERE [name] = 'Person')
BEGIN
EXEC ('CREATE SCHEMA [Person]')
END
IF NOT EXISTS (SELECT TOP (1) 1 FROM [sys].[tables] AS T
INNER JOIN [sys].[schemas] AS S ON S.schema_id = T.schema_id
WHERE T.[name] = 'Guests' AND S.[name] = 'Person')
BEGIN
EXEC ('CREATE TABLE [Person].[Guests]
(
[GuestId] INT IDENTITY(1, 1) NOT NULL,
[Forename] NVARCHAR(100) NOT NULL,
[Surname] NVARCHAR(100) NOT NULL,
[Email] VARCHAR(255) NOT NULL,
[BirthDate] DATETIME2 NULL,
CONSTRAINT [PK_Guests_GuestId] PRIMARY KEY CLUSTERED ([GuestId]),
CONSTRAINT [UX_Guests_Email] UNIQUE([Email])
)')
END
NOTICE: CREATE SCHEMA AND CREATE TABLE NEED COMPLETLY SEPARATED BATCH TO EXECUTE
TO MORE DESCRIPTION VISIT MICROSOFT DOCS WEBSITE :)
As of SQL Server 2005 version 9.0 you can use the INFORMATION_SCHEMA.SCHEMATA view to check if the schema exists:
IF NOT EXISTS (
SELECT SCHEMA_NAME
FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = '<schema name>' )
BEGIN
EXEC sp_executesql N'CREATE SCHEMA <schema name>'
END
GO
INFORMATION_SCHEMA views are the ISO standard and are generally preferable; these were adopted to make the syntax more consistent across different SQL database platforms.
Note that the CREATE SCHEMA must be run in its own batch