Written by Thomas Harlan, Reporting Services Team - iatricSystems
For today's blog post, we want to help solve this common problem: how to clean up custom objects like #Temp or ##Temp tables in a SQL database when they are no longer needed.
Introduction
As we create custom objects in a SQL database like the DR, we need to be mindful of cleaning them up when they are no longer needed, or when we need to clear an old object out, before re-creating it.
The first type of SQL object we need to clean up that comes to mind are:
#Temp or ##Temp tables
TEMP tables in SQL have a number of quirks necessitating housekeeping:
WARNING! Here’s an extra word of caution. If you have a stored procedure that creates a #temp table, and then that SP invokes another SP that also creates a #temp table with the same name, on some versions of SQL Server you will not get a second temp table with a different structure. Instead, the second SP will be given the first #temp table and may then fail due to missing fields or primary key violations.
The duplicated CREATE TABLE statement in the second SP will not error out. Despite what the MS documentation says, the engine will not add a numeric suffix to differentiate them internally. Instead you'll get an unexpected error and won’t know why.
As a result, it’s best practice to name each #temp table uniquely when you have SP’s calling SP’s.
Solution
Given all that, there are two ways to clean up the #temp tables after you’re done with them:
In pre-SQL 2016 environments you add code like this at the bottom of your stored procedure or script:
IF OBJECT_ID('tempdb.dbo.#DS') IS NOT NULL DROP TABLE #DS;
NOTE! When you do this, make sure to confirm that your temp database is really called tempdb.
In a SQL 2016+ environment, things are easier! A new clause has been added to the DROP TABLE syntax, so you can do this instead:
DROP TABLE IF EXISTS #Docs, #DS, #Templates, #ResultSet ;
So much better! We can just send a whole list of #temp tables, and they are dropped if they exist, and no error if they do not. Plus, we don’t have to worry about tempdb not being the temp db!
But wait… if they added this for #temp tables, did they add it for other objects as well?
Yes, they did!
We also recommend DROP-ing Procedures, Views, Functions and so on when you need to re-create them.
There are a number of reasons for this approach:
In pre-SQL 2016 versions, you need to do that DROP like this:
For a scalar function:
USE [zcus]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF EXISTS ( SELECT [type]
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[FunctionName]')
AND [type] IN ( N'FN', N'IF',N'FS' ) )
BEGIN
DROP FUNCTION [dbo].[FunctionName]
END ;
GO
For a table-valued function:
USE [zcus]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF EXISTS ( SELECT [type]
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[YourFunctionName]')
AND [type] IN ( N'FT',N'TF' ) )
BEGIN
DROP FUNCTION [dbo].[YourFunctionName]
END ;
GO
For a stored procedure:
USE [zcus];
GO
SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
IF EXISTS ( SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[YourProcedureName]')
AND type IN ( N'P', N'PC' ) )
BEGIN
DROP PROCEDURE [dbo].[YourProcedureName]
END ;
GO
And finally for a view:
USE [zcus]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF EXISTS ( SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[YourViewName]')
AND [type] IN ( N'V' ) )
BEGIN
DROP VIEW [dbo].[YourViewName]
END ;
GO
Note that in this approach we need to switch to the database and also set the [type] of the object we are looking for. And there is a fair bit of code to cut/paste/edit into each object script.
Post-SQL 2016 we have a much cleaner approach:
For a scalar function:
USE [zcus]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
DROP FUNCTION IF EXISTS [dbo].[YourScalarFunctionNameHere] ;
GO
For a stored procedure:
USE [zcus]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
DROP PROCEDURE IF EXISTS [dbo].[ReplaceWithYourSpName] ;
GO
For a table-valued function:
USE [zcus]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
DROP FUNCTION IF EXISTS [dbo].[TableValuedFunctionNameHere] ;
GO
And for a view:
USE [zcus]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
DROP VIEW IF EXISTS [dbo].[YourViewNameHere] ;
GO
There you go!
Extra Credit
Make code templates for each kind of object and always start from them. Then the DROP code can be built in and you won’t have to hunt for it!
Update all of your off-line copies of your code (you ARE keeping an off-line copy, right? Of every single custom SQL object in your database? If not, do that RIGHT NOW. Always work on an off-line copy and update it into LIVE).
And…
As ever, if you need help with MEDITECH DR optimization, reporting, extracting, index creation or analysis please feel free to give your iatricSystems Account Executive a call or email info@iatric.com to discuss how we can help support your team!