SQL DBA Survival Guide

User Defined Objects

Views

A view is a virtual table based on the result-set of an SQL statement. A view contains rows and columns, just like a real table. The fields in a view are fields from one or more real tables in the database.

Views can join multiple tables to present the data as if the data were coming from a single table.

Views in SQL offer advantages like data security, simplified complexity, and data consistency, but can also lead to performance issues.

Naming views with a preceding v, v_ or vw_ helps to differentiate between tables and view when writing and reading code.

WorldPop Demo Data

This code will be used for the exercises in this section.

Execute script 0501-01-05 to create a WorldPop table and add data to it.

-- 0501-01-10 Demonstration Code ================
-- Show all the rows in the WorldPop table
Select all the rows in the WorldPop table
SELECT * FROM [dbo].[WorldPop]

Creating Views

The Create View command will create a new view.

Note: Before objects such as views, procedures, functions and triggers can be created or altered, all dependencies must already exist. Additionally the CREATE or ALTER statement must be the first statement in a batch, any code above in the script should be followed with GO,

Syntax

CREATE VIEW <ViewName>
AS
sql_statement / code

Notice that in views the output column names must be unique.

-- Code fails because of ambiguous column names from the source tables
CREATE VIEW v_SocialMediaFriends AS
SELECT F.[Name], F.[Friends], L.[Name], L.[Friends]
FROM [Facebook] F
JOIN [LinkedIn] L
ON L.[Name] = F.[Name];
GO

CreatingViews01

The above code will work after adding column aliases

-- 0501-02-05 Demonstration Code ================
CREATE VIEW [v_SocialMediaFriends] AS
SELECT F.[Name] AS F_Name, F.[Friends] AS F_Friends, L.[Name] AS L_Name, L.[Friends] AS L_Friends
FROM [Facebook] F
JOIN [LinkedIn] L
ON L.[Name] = F.[Name];
GO

-- 0501-02-10 Demonstration Code ================
-- Run the v_SocialMediaFriends view
SELECT * FROM [v_SocialMediaFriends] 

CreatingViews02

Altering Views

The Alter View command will modify an existing view.

Note: Before objects such as views, procedures, functions and triggers can be created or altered, all dependencies must already exist. Additionally the CREATE or ALTER statement must be the first statement in a batch, any code above in the script should be followed with GO,

Syntax

ALTER VIEW <ViewName>
AS
sql_statement / code

-- 0501-03-10 Demonstration Code ================
-- Alter the v_SocialMediaFriends view
ALTER VIEW v_SocialMediaFriends AS
SELECT F.[Name] AS F_Name, F.[Friends] AS F_Friends, L.[Name] AS L_Name, L.[Friends] AS L_Friends
FROM [Facebook] f
FULL OUTER JOIN [LinkedIn] l
ON f.[Name] = l.[Name]
GO

-- 0501-03-10 Demonstration Code ================
-- Run the v_SocialMediaFriends view
SELECT * FROM [v_SocialMediaFriends]

AlterView01

Materialized Views

Unlike a normal (virtual) view, which doesn't store data itself but dynamically retrieves it when queried, a materialized view is precomputed and stored as a table-like structure. This can enhance query performance by avoiding the need to recompute results every time the view is queried.

Nested Views

Nested views include other dependencies which may include other views.

Note: Before objects such as views, procedures, functions and triggers can be created or altered, all dependencies must already exist. Additionally the CREATE or ALTER statement must be the first statement in a batch, any code above in the script should be followed with GO,

Nested views can lead to deployment and performance issues.

To script out a view with its dependencies

  1. Right-click on database
  2. Select Task > Generate SQL script
  3. Choose Select specific database objects
  4. Expand Views
  5. Check the desired view
  6. Click the Next button
  7. Click the Advanced button
  8. Set "Generate script for all dependent objects" = True
  9. Complete the wizard

Updating Data from a View

Updating data in dependent tables can be tricky with views and is not commonly implemented.

Single table view

Updating data can be simple as long as the view is created based on one single table then direct "Update View" statement would work as long as it does not contain something like GROUP BY.

Multi-Table view

But if the view is created based on multiple tables it becomes more complicated.

The View can be updated if based on multiple tables as long as the update only affects one table. The Single-table view rules above will apply.

If multiple tables are to be updated by a view, then advanced methods such as triggers need to be implemented.

 

Stored Procedures

Creating Stored Procedures

The Create Procedure command will create a new stored procedure.

Note: Before objects such as views, procedures, functions and triggers can be created or altered, all dependencies must already exist. Additionally the CREATE or ALTER statement must be the first statement in a batch, any code above in the script should be followed with GO,

Syntax

CREATE PROCEDURE <ProcedureName>
AS
sql_statement / code

Ensure the WorldPop table and data exists. (Script 0409-01-05)

It is a good practice to add comments to scripts, this is especially true for stored procedures. It can provide information to others about what the script is used for and how to use it.

-- 0502-01-05 Demonstration Code ================
CREATE PROCEDURE sp_WorldPopList
AS
/*
List all rows ordered by [Land Area (km)] DESC
Usage: EXEC sp_WorldPopList
*/
SELECT * FROM [dbo].[WorldPop]
GO

-- 0502-01-10 Demonstration Code ================
-- Execute the SP that shows all the rows in the WorldPop table
EXEC sp_WorldPopList

Altering Stored Procedures

The Alter Procedure command will modify an existing stored procedure.

Note: Before objects such as views, procedures, functions and triggers can be created or altered, all dependencies must already exist. Additionally the CREATE or ALTER statement must be the first statement in a batch, any code above in the script should be followed with GO.

Syntax

ALTER PROCEDURE <ProcedureName>
AS
sql_statement / code

-- 0502-02-05 Demonstration Code ================
-- Alter the existing SP sp_WorldPopList to add ORDER BY
ALTER PROCEDURE sp_WorldPopList
AS
/*
List all rows ordered by [Land Area (km)] DESC
Usage: EXEC sp_WorldPopList
*/
SELECT * FROM [dbo].[WorldPop]
ORDER BY [Land Area (km)] DESC
GO

-- 0502-02-10 Demonstration Code ================
-- Execute the SP that shows all the rows in the WorldPop table
-- with ORDER BY
EXEC sp_WorldPopList

Magic 8 Ball Procedure

This SP will emulate the Magic 8 Ball toy. Ask it a question and it will return a random answer.

This script uses a parameter to accept a question (@Question) as a nvarchar.

-- 0502-03-05 Demonstration Code ================
-- Create Majic8Ball Procedure
CREATE PROCEDURE [dbo].[sp_Magic8Ball]
(
@Question nvarchar(max)
)
AS
/*
Provide a random answer to a question
Usage: EXEC sp_Magic8Ball 'any question'
*/
BEGIN
SET NOCOUNT ON

DECLARE @Answer nvarchar(100)
DECLARE @Magic8BallAnswers TABLE
(
Answer_ID int
,Answer_Type nvarchar(25)
,Answer_Text nvarchar(100)
)

INSERT INTO @Magic8BallAnswers
VALUES (1,'Positive','It is certain')
,(2,'Positive','It is decidedly so')
,(3,'Positive','Without a doubt')
,(4,'Positive','Yes definitely')
,(5,'Positive','You may rely on it')
,(6,'Positive','As I see it, yes')
,(7,'Positive','Most likely')
,(8,'Positive','Outlook good')
,(9,'Positive','Yes')
,(10,'Positive','Signs point to yes')
,(11,'Neutral','Reply hazy try again')
,(12,'Neutral','Ask again later')
,(13,'Neutral','Better not tell you now')
,(14,'Neutral','Cannot predict now')
,(15,'Neutral','Concentrate and ask again')
,(16,'Negative','Don''t count on it')
,(17,'Negative','My reply is no')
,(18,'Negative','My sources say no')
,(19,'Negative','Outlook not so good')
,(20,'Negative','Very doubtful')

SELECT TOP 1 @Answer = Answer_Text FROM @Magic8BallAnswers ORDER BY ABS(CHECKSUM(NEWID()) % 100)
PRINT @Answer
END

-- 0502-03-10 Demonstration Code ================
-- Test the Procedure Majic8Ball
EXEC sp_Magic8Ball 'Does the code work?'

Enhanced SP

In order for this SP to work properly, ensure the WorldPop table exist and the data is imported.

-- 0502-04-05 Demonstration Code ================
-- Procedure with parameters to control result sorting
CREATE PROCEDURE sp_WorldPopList
@Sort [varchar](128),
@Order [varchar](128) = 'ASC',
@Count [varchar](3)=10
AS
/*
List all rows ordered by passed value
Usage
EXEC sp_WorldPopList @Sort='Fert Rate'
EXEC sp_WorldPopList @Sort='Migrants', @Order='DESC'
EXEC sp_WorldPopList @Sort='Migrants', @Order='ASC'
EXEC sp_WorldPopList @Sort='Net Change', @Order='DESC', @Count = 15
*/
BEGIN
SET NOCOUNT ON
DECLARE @SqlCode [nvarchar](MAX)
SET @SqlCode = N'SELECT TOP(' + @Count + ') * FROM [dbo].[WorldPop]' +
' ORDER BY [' + @Sort + '] ' + @Order
PRINT (@sqlCode)
EXEC(@sqlCode)
END
GO

Various Queries

EXEC sp_WorldPopList @Sort='Fert Rate'

EXEC sp_WorldPopList @Sort='Migrants', @Order='DESC'

EXEC sp_WorldPopList @Sort='Migrants', @Order='ASC'

EXEC sp_WorldPopList @Sort='Net Change', @Order='DESC', @Count = 15

 

Functions

A function is prepared SQL code that is saved, so the code can be reused repeatedly.

Functions are stored in a database. Functions added to the server are "user defined" functions (UDF)

Database > Programmability > Functions

SQL Server comes with many built-in functions.

<DatabaseName> > Programmability > Functions > System Functions

Additionally, the master database contains built-in functions that are available globally to the instance.

master > Programmability > Functions > System Functions

Functions are stored in categorized sub hives

  • Table-valued Functions
  • Scalar-valued Functions
  • Aggregate Functions

Stored Procedures vs Functions

Stored procedures can take both input and output parameters but Functions take can only input parameters. Functions cannot return values of type text.

Stored procedures perform larger activities and can modify data, whereas functions focus on computations and data retrieval, providing flexibility in SQL statements.

Naming functions with a preceding f_, fn_, ufn_ or udf_ helps to differentiate between other database objects when writing and reading code.

Table-valued Functions

Table Valued Functions return a dataset. They are used in the FROM clause.

They behave identically to a subquery in terms of how you'd incorporate into a multi-table FROM clause. Namely, if it needs columns from those tables to execute you'd SQL Standard LATERAL JOIN (i.e., CROSS APPLY) the reference and you'd get iterative / correlated execution, otherwise you can just treat its output like any other relation that you'd combine using a join predicate.

Generally, inline table-valued functions perform better than scalar functions, as they can be optimized by the query optimizer and benefit from parallelism. Multi-statement table-valued functions, on the other hand, can be slower than scalar functions, as they incur more overhead and cannot be optimized.

Scalar-valued Functions

Scalar Valued Functions return a value. They are typically used in the SELECT or WHERE clause.

Aggregate Functions

An aggregate function is a mathematical computation involving a range of values that results in just a single value expressing the significance of the accumulated data it is derived from.

 Aggregate functions are often used to derive descriptive statistics.

The standard aggregate functions are MIN, MAX, AVG, SUM, and COUNT.

Creating Functions

The Create Function command will create a new function.

Note: Before objects such as views, procedures, functions and triggers can be created or altered, all dependencies must already exist. Additionally the CREATE or ALTER statement must be the first statement in a batch, any code above in the script should be followed with GO.

The return type will determine the function type and the correct function type will automatically be stored in the correct hive.

Syntax (Scalar-valued function)

CREATE FUNCTION <FunctionName> ()
RETURNS <DataType>
AS
sql_statement / code

-- 0503-04-05 Demonstration Code ================
-- Create fn_IsAzureMI function
CREATE FUNCTION [dbo].[fn_IsAzureMI]()
RETURNS [bit]
AS
/*
=======================================
Name: fn_IsAzureMI
Purpose: Utility to determine if the script is running on an Azure SQL Managed Instance.
Parameters: none
Usage: SET @IsAzureMI = (SELECT [dbo].[fn_IsAzureMI] ())
Returns [bit]:
0 if NOT running on an Azure Managed Instance
1 if running on an Azure Managed Instance
Recommended Cadence:
Author: TJ Elias
Version: 231212
=======================================
*/
BEGIN
DECLARE @ReturnValue [int],
@EngineEdition [int],
@IsAzureMI [int]

SET @ReturnValue = 1
SET @IsAzureMI = 0
SET @EngineEdition = CAST((SELECT SERVERPROPERTY ('EngineEdition')) AS int)

IF @EngineEdition = 8
SET @IsAzureMI = 1

RETURN @IsAzureMI
END
GO
/* Code End */

SELECT [dbo].[fn_IsAzureMI] ()

Altering Functions

The Alter Function command will modify an existing function.

Note: Before objects such as views, procedures, functions and triggers can be created or altered, all dependencies must already exist. Additionally the CREATE or ALTER statement must be the first statement in a batch, any code above in the script should be followed with GO.

Syntax (Scalar-valued function)

ALTER FUNCTION <FunctionName> ()
RETURNS <DataType>
AS
sql_statement / code

 

Triggers

An SQL trigger allows you to specify SQL actions that will be executed automatically when a specific event occurs in the database.

For example, you can use a trigger to automatically update a record in one table whenever a record is inserted into another table.

Naming functions with a preceding t_ or tri_ helps to differentiate between other database objects when writing and reading code.

Creating Triggers

The Create Trigger command will create a new trigger.

Note: Before objects such as views, procedures, functions and triggers can be created or altered, all dependencies must already exist. Additionally the CREATE or ALTER statement must be the first statement in a batch, any code above in the script should be followed with GO.

Altering Triggers

The Alter Trigger command will modify an existing trigger.

Note: Before objects such as views, procedures, functions and triggers can be created or altered, all dependencies must already exist. Additionally the CREATE or ALTER statement must be the first statement in a batch, any code above in the script should be followed with GO.

 

Useful Tips & Tricks

sp_CreateEmptyObject

This script uses parameters and is a helpful SP that will create an object. It may seem like an overkill for what it does, but the value of this script will be demonstrated later.

Parameters can be passed to a SP to expand functionality. Parameters can be mandatory or optional. Optional parameters are typically defined last.

This procedure is useful for other code that can simply depend on an object already existing so it only needs to Alter the object. Future demonstration code will illustrate how it is used.

-- 0502-01-05 Demonstration Code ================
-- Create a procedure that will create an empty object
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_CreateEmptyObject]') AND type in (N'P', N'PC'))
EXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE [dbo].[sp_CreateEmptyObject] AS'
GO

ALTER PROCEDURE [dbo].[sp_CreateEmptyObject]
@Type [varchar](2),
@Name [nvarchar](128),
@Schema [nvarchar](50) = 'dbo'
AS
/*
=======================================
Name: sp_CreateEmptyObject
Purpose: Utility to Create an empty Stored Procedure
Parameters:
@Type - Object type {V,P,F,T}
@Name - Procedure name
[@Schema] - (optional) Schema name
Prototype:
EXEC [dbo].[sp_CreateEmptyObject] @Type, @Name [, @Schema]
Usage:
EXEC [dbo].[sp_CreateEmptyObject] @Type="P", @Name='myProcName'
EXEC [dbo].[sp_CreateEmptyObject] @Type="P", @Name='myProcName', @Schema='mySchemaName'
=======================================
*/
BEGIN
SET NOCOUNT ON

DECLARE @FullName [nvarchar](128),
@sqlCode [nvarchar](MAX)

SET @FullName = '[' + @Schema + '].[' + @Name + ']'
SET @sqlCode = N''

IF @Type = 'V'
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(@FullName) AND type in (N'V'))
SET @sqlCode = N'CREATE VIEW ' + @FullName + 'AS BEGIN SELECT 1 END'

IF @Type = 'P'
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(@FullName) AND type in (N'P', N'PC'))
SET @sqlCode = N'CREATE PROCEDURE ' + @FullName + 'AS BEGIN SELECT 1 END'

IF @Type = 'F'
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(@FullName) AND type in (N'FN', N'IF', N'TF', N'FS', N'FT' ))
SET @sqlCode = N'CREATE FUNCTION ' + @FullName + '() RETURNS [bit] AS BEGIN RETURN 1 END'

IF @Type = 'T'
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(@FullName) AND type in (N'TR'))
SET @sqlCode = N'CREATE TRIGGER ' + @FullName + 'AS BEGIN SELECT 1 END'

IF @sqlCode <> N''
EXEC(@sqlCode)
END