TRY...CATCH doesn't seem to work - sql

I have the following piece of code that's just to make sure that the temporary table doesn't exist. If the table exist I want to truncate it.
CREATE TABLE #LookupLinks(
[SyncID] uniqueidentifier,
[Name] nvarchar(50),
[SQLTable] nvarchar(50)
) --I create this just to test my try-catch
BEGIN TRY
CREATE TABLE #LookupLinks(
[SyncID] uniqueidentifier,
[Name] nvarchar(50),
[SQLTable] nvarchar(50)
)
END TRY
BEGIN CATCH
PRINT N'#LookupLinks already existed and was truncated.';
TRUNCATE TABLE #LookupLinks
END CATCH
What I want this to do:
The temp-table is created
Attempt to create it again
error sends us into the catch
table is truncated and everything continues as normal
What happens:
ERROR: There is already an object named '#LookupLinks' in the database.
What am I doing wrong here?

This is because SQL Server parses and validates the whole batch. So when parsing the second CREATE TABLE statement, it errors out saying:
There is already an object named '#LookupLinks' in the database.
See this example:
IF 1 = 1 BEGIN
CREATE TABLE #temp(col INT)
END
ELSE BEGIN
CREATE TABLE #temp(col INT)
END
It produces an error saying:
There is already an object named '#temp' in the database.
The workaround is to use Dynamic SQL.
-- CREATE the table for testing
IF OBJECT_ID('tempdb..#LookupLinks') IS NOT NULL
DROP TABLE #LookupLinks
CREATE TABLE #LookupLinks(
[SyncID] uniqueidentifier,
[Name] nvarchar(50),
[SQLTable] nvarchar(50)
)
-- Final query
IF OBJECT_ID('tempdb..#LookupLinks') IS NOT NULL BEGIN
TRUNCATE TABLE #LookupLinks
PRINT N'#LookupLinks already existed and was truncated.'
END
ELSE BEGIN
DECLARE #sql NVARCHAR(MAX) = ''
SELECT #sql = '
CREATE TABLE #LookupLinks(
[SyncID] uniqueidentifier,
[Name] nvarchar(50),
[SQLTable] nvarchar(50)
)'
EXEC sp_executesql #sql
PRINT N'#LookupLinks was created.'
END
If you do not have the first CREATE TABLE statement,your query will work just fine. Or if you put a GO before the BEGIN TRY.
IF OBJECT_ID('tempdb..#LookupLinks') IS NOT NULL
DROP TABLE #LookupLinks -- DROP FIRST
CREATE TABLE #LookupLinks(
[SyncID] uniqueidentifier,
[Name] nvarchar(50),
[SQLTable] nvarchar(50)
) --I create this just to test my try-catch
GO
BEGIN TRY
CREATE TABLE #LookupLinks(
[SyncID] uniqueidentifier,
[Name] nvarchar(50),
[SQLTable] nvarchar(50)
)
END TRY
BEGIN CATCH
PRINT N'#LookupLinks already existed and was truncated.';
TRUNCATE TABLE #LookupLinks
END CATCH
Still, it's because SQL server parses and validates the whole batch. The GO statement will put the statements into their own batches, thus the error is now not happening.
Even CeOnSql's answer will work fine.

I think what you really want to achieve is this:
IF OBJECT_ID('tempdb..#LookupLinks') IS NOT NULL --Table already exists
BEGIN
TRUNCATE TABLE #LookupLinks
PRINT N'#LookupLinks already existed and was truncated.';
END
ELSE
BEGIN
CREATE TABLE #LookupLinks(
[SyncID] uniqueidentifier,
[Name] nvarchar(50),
[SQLTable] nvarchar(50)
)
END

TRY CATCH is for run time error. What you are getting is a compile time error. Add a PRINT 1 before your statement and you'll see that nothing is getting executed.
print 1
CREATE TABLE #LookupLinks(
[SyncID] uniqueidentifier,
[Name] nvarchar(50),
[SQLTable] nvarchar(50)
);
BEGIN TRY
CREATE TABLE #LookupLinks(
[SyncID] uniqueidentifier,
[Name] nvarchar(50),
[SQLTable] nvarchar(50)
);
END TRY
BEGIN CATCH
PRINT N'#LookupLinks already existed and was truncated.';
TRUNCATE TABLE #LookupLinks
END CATCH

Related

SQL Incorrect Syntax Near 'GO'

I am getting the error in my sproc and I cannot figure out why. I have looked at other, almost identical questions like this Here and the answers aren't doing the trick for me. the syntax error is at the 'Go' right after the database creation.
USE [DATABASENAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Sproc]
#Id int
AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS (SELECT name FROM sys.databases WHERE name =
N'Name')
create database Name;
GO
CREATE TABLE [Name].[dbo].[Account](
[Id] [int] IDENTITY(1,1) NOT NULL,
[AccountId] [int] NOT NULL
);
GO is not allowed in stored procedures. It separates batches and a procedure itself is one batch which cannot be separated.
You could use one procedure to create the database, then a second procedure to create the table.
Edit
Actually you could do it in one procedure:
CREATE PROCEDURE [dbo].[Sproc]
AS
BEGIN
EXEC ('USE [Master]; CREATE DATABASE [name]')
EXEC ('USE [Name]; CREATE TABLE [name].dbo.[Account] (id int)')
END

How can I pass tables to stored procedures?

I have a table of data like this, and one procedure is going to populate data in it like this,
DECLARE #ClaimChanges TABLE (
ChangeType NVARCHAR(10)
,contract_id int NOT NULL
,dispatch_id int NOT NULL
,dispatch_claim_id int NOT NULL
,item_no VARCHAR(100) NULL
,old_units VARCHAR(100) NULL
);
I would then like to pass that data to a different stored procedure which would be defined like this,
CREATE procedure [dbo].[ct_audit_oncost](
#table TABLE readonly,
#OutValue nvarchar(255) = null output
)
as
-- some stuff
go
I gather this is not possible as I am getting an error,
Incorrect syntax near the keyword 'TABLE'.
Table valued parameters are supported since 2008 version.
However, you can't just pass any table you want, first you need to define a user defined table type:
CREATE TYPE dbo.MyUDT as TABLE
(
ChangeType NVARCHAR(10)
,contract_id int NOT NULL
,dispatch_id int NOT NULL
,dispatch_claim_id int NOT NULL
,item_no VARCHAR(100) NULL
,old_units VARCHAR(100) NULL
)
Then you can use it in your stored procedure:
CREATE procedure [dbo].[ct_audit_oncost]
(
#table dbo.MyUDT readonly,
#OutValue nvarchar(255) = null output
)
as
-- some stuff
go
Please note you should also use it to declare the table to send to the database:
DECLARE #Out nvarchar(255)
DECLARE #ClaimChanges as dbo.MyUdt
INSERT INTO #ClaimChanges (ColumnsList) VALUES (ValuesList)
EXEC ct_audit_oncost #ClaimChanges, #Out output

T-SQL can't excute my procedure

My code:
CREATE TABLE test (id INT NOT NULL PRIMARY KEY IDENTITY(1,1),
text VARCHAR(255)
);
GO
CREATE PROCEDURE testProc(#string VARCHAR(255))
AS
BEGIN
INSERT INTO test (text) VALUES (#string);
SELECT * FROM test;
END
GO
EXEC testProc('Test01')
The error I get after running it:
Incorrect syntax near 'Test01'.*
I want to insert 'Test01' into my table test with the help of the proc testProc, but it doesn't work.
You just need to omit the parentheses.
EXEC testProc #string = 'Test01';

Deletion\Creation of Temp tables in SQL Server 2008

I have SQL code like this
IF Object_id('tempdb..#empDate) IS NOT NULL
DROP TABLE #empDate
CREATE TABLE #empDate
(
[empID] INT,
[AddLoc] VARCHAR(1000)
)
After the above code some more lines of SQL follow and then it is repeated.
I get the following error.
Msg 2714, Level 16, State 1, Line 589
There is already an object named '#empDate' in the database.
I replaced the
IF Object_id('tempdb..#empDate) IS NOT NULL
with
IF Object_id('tempdb..#empDate%) IS NOT NULL
As it is written on the forums that SQL Server appends number to the subsequent temp table(s).
Source:
Check if a temporary table exists and delete if it exists before creating a temporary table
http://blog.sqlauthority.com/2009/05/17/sql-server-how-to-drop-temp-table-check-existence-of-temp-table/
http://blog.sqlauthority.com/2009/03/29/sql-server-fix-error-msg-2714-level-16-state-6-there-is-already-an-object-named-temp-in-the-database/
I am using Microsoft SQL Server 2008 on Windows 7 Enterprise.
I am not able to understand the cause of the error.
Please help.
Sample One
This will fail......
Executing the same code again, will throw the error you are getting now
IF Object_id('tempdb..#empDate') IS NOT NULL
BEGIN
DROP TABLE #empDate
END
CREATE TABLE #empDate
(
[empID] INT,
[AddLoc] VARCHAR(1000)
)
IF Object_id('tempdb..#empDate') IS NOT NULL
BEGIN
DROP TABLE #empDate
END
CREATE TABLE #empDate
(
[empID] INT,
[AddLoc] VARCHAR(1000)
)
Sample Two (Fixed)
IF Object_id('tempdb..#empDate') IS NOT NULL
BEGIN
DROP TABLE #empDate
END
CREATE TABLE #empDate
(
[empID] INT,
[AddLoc] VARCHAR(1000)
)
GO --<-- Adding this Batch Separator will eliminate the Error
IF Object_id('tempdb..#empDate') IS NOT NULL
BEGIN
DROP TABLE #empDate
END
CREATE TABLE #empDate
(
[empID] INT,
[AddLoc] VARCHAR(1000)
)
Test
If you try Executing the following Statements in ONE BATCH they will fail even though there isnt any table at all with the name #empDate, it will not even execute the very 1st Create table Statement. and will throw an error.
CREATE TABLE #empDate
(
[empID] INT,
[AddLoc] VARCHAR(1000)
)
DROP TABLE #empDate
CREATE TABLE #empDate
(
[empID] INT,
[AddLoc] VARCHAR(1000)
)
But if you separate all the statement in separate batches they will be executed successfully something like this..
CREATE TABLE #empDate
(
[empID] INT,
[AddLoc] VARCHAR(1000)
)
GO
DROP TABLE #empDate
GO
CREATE TABLE #empDate
(
[empID] INT,
[AddLoc] VARCHAR(1000)
)
GO
I would just drop your table without any pre-checks.
Then write/run the script clean.
Once done using the temp table, drop it at the end of your script.
So run this unconditionally
DROP TABLE #empDate
Then write/run your script and make sure you have this line at the end of your script.
pass database name with object_id
example :
DECLARE #db_id int;
DECLARE #object_id int;
SET #db_id = DB_ID(N'AdventureWorks2012');
SET #object_id = OBJECT_ID(N'AdventureWorks2012.Person.Address');
IF #db_id IS NULL
BEGIN;
PRINT N'Invalid database';
END;
ELSE IF #object_id IS NULL
BEGIN;
PRINT N'Invalid object';
END;
ELSE
BEGIN;
SELECT * FROM sys.dm_db_index_operational_stats(#db_id, #object_id, NULL, NULL);
END;
GO

Mirroring Table Modifications

I have a set of tables that are used to track bills. These tables are loaded from an SSIS process that runs weekly.
I am in the process of creating a second set of tables to track adjustments to the bills that are made via the web. Some of our clients hand key their bills and all of those entries need to be backed up on a more regular schedule (the SSIS fed data can always be imported again so it isn't backed up).
Is there a best practice for this type of behavior? I'm looking at implementing a DDL trigger that will parse the ALTER TABLE call and change the table being called. This is somewhat painful, and I'm curious if there is a better way.
I personally would have the SSIS-fed tables in one database (set to simple recovery mode) and the other tables in a separate database on the same server which is set to full recovery mode,. Then I would set up backups on the second datbase on a regular schedule. A typical backup schedule would be full backup once a week, differntials nightly and transaction backups every 15-30 minutes depending on how much data is being input.) Be sure to periodically test recovering the backups, learning how to do that when the customer is screaming becasue the datbase is down isn;t a good thing.
I ended up using a DDL trigger to make a copy of changes from one table to the other. The only problem is that if a table or column name contains part of a reserved word - ARCH for VARCHAR - it will cause problems with the modification script.
Thanks, once again, to Brent Ozar for error checking my thoughts before I blogged them.
-- Create pvt and pvtWeb as test tables
CREATE TABLE [dbo].[pvt](
[VendorID] [int] NULL,
[Emp1] [int] NULL,
[Emp2] [int] NULL,
[Emp3] [int] NULL,
[Emp4] [int] NULL,
[Emp5] [int] NULL
) ON [PRIMARY];
GO
CREATE TABLE [dbo].[pvtWeb](
[VendorID] [int] NULL,
[Emp1] [int] NULL,
[Emp2] [int] NULL,
[Emp3] [int] NULL,
[Emp4] [int] NULL,
[Emp5] [int] NULL
) ON [PRIMARY];
GO
IF EXISTS(SELECT * FROM sys.triggers WHERE name = ‘ddl_trigger_pvt_alter’)
DROP TRIGGER ddl_trigger_pvt_alter ON DATABASE;
GO
-- Create a trigger that will trap ALTER TABLE events
CREATE TRIGGER ddl_trigger_pvt_alter
ON DATABASE
FOR ALTER_TABLE
AS
DECLARE #data XML;
DECLARE #tableName NVARCHAR(255);
DECLARE #newTableName NVARCHAR(255);
DECLARE #sql NVARCHAR(MAX);
SET #sql = ”;
-- Store the event in an XML variable
SET #data = EVENTDATA();
-- Get the name of the table that is being modified
SELECT #tableName = #data.value(‘(/EVENT_INSTANCE/ObjectName)[1]‘, ‘NVARCHAR(255)’);
-- Get the actual SQL that was executed
SELECT #sql = #data.value(‘(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]‘, ‘NVARCHAR(MAX)’);
-- Figure out the name of the new table
SET #newTableName = #tableName + ‘Web’;
-- Replace the original table name with the new table name
-- str_replace is from Robyn Page and Phil Factor’s delighful post on
-- string arrays in SQL. The other posts on string functions are indispensible
-- to handling string input
--
-- http://www.simple-talk.com/sql/t-sql-programming/tsql-string-array-workbench/
-- http://www.simple-talk.com/sql/t-sql-programming/sql-string-user-function-workbench-part-1/
--http://www.simple-talk.com/sql/t-sql-programming/sql-string-user-function-workbench-part-2/
SET #sql = dbo.str_replace(#tableName, #newTableName, #sql);
-- Debug the SQL if needed.
--PRINT #sql;
IF OBJECT_ID(#newTableName, N’U’) IS NOT NULL
BEGIN
BEGIN TRY
-- Now that the table name has been changed, execute the new SQL
EXEC sp_executesql #sql;
END TRY
BEGIN CATCH
-- Rollback any existing transactions and report the full nasty
-- error back to the user.
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION;
DECLARE
#ERROR_SEVERITY INT,
#ERROR_STATE INT,
#ERROR_NUMBER INT,
#ERROR_LINE INT,
#ERROR_MESSAGE NVARCHAR(4000);
SELECT
#ERROR_SEVERITY = ERROR_SEVERITY(),
#ERROR_STATE = ERROR_STATE(),
#ERROR_NUMBER = ERROR_NUMBER(),
#ERROR_LINE = ERROR_LINE(),
#ERROR_MESSAGE = ERROR_MESSAGE();
RAISERROR(‘Msg %d, Line %d, :%s’,
#ERROR_SEVERITY,
#ERROR_STATE,
#ERROR_NUMBER,
#ERROR_LINE,
#ERROR_MESSAGE);
END CATCH
END
GO
ALTER TABLE pvt
ADD test INT NULL;
GO
EXEC sp_help pvt;
GO
ALTER TABLE pvt
DROP COLUMN test;
GO
EXEC sp_help pvt;
GO