Download as pdf or txt
Download as pdf or txt
You are on page 1of 212

Practical Sql

Microsoft Sql Server T-SQL


for Beginners
2nd Edition
By
Mark O'Donovan
Copyright © 2019 Mark O’Donovan
All rights reserved.
Contents

Software and Sample data


Overview
Section 1. Sql Server Install and Tour
Section 2. Starting Sql Development
Section 3. Advanced Queries
Section 4. Sql Beyond the Basics
Conclusion
Quiz Answers
Useful Websites
Copyright

All rights reserved.

No part of this publication may be reproduced or transmitted in any form or


by any means without written permission from the author.

Disclaimer
Although the author and publisher have made every effort to ensure that the
information in this book was correct at press time, the author and publisher do
not assume and hereby disclaim any liability to any party for any loss, damage,
or disruption caused by errors or omissions, whether such errors or omissions
result from negligence, accident, or any other cause.

Information sold in this book is sold without warranty, either expressed or


implied.

Title: Practical Sql - Microsoft Sql Server T-SQL for Beginners – Second
Edition

Version: 2.0
Software and Sample Data
The examples in this book used Sql Server 2017 Express which is as of
writing this book a free version of sql server available for download from
Microsoft.

You can download all the sample data and examples for this book from

https://github.com/techstuffy/Practical-Sq

There should be no problem with running these exercises on later versions of


Sql Server but we cannot give a 100% guarantee.

Most examples will run on previous versions of Microsoft Sql Server but
some functions might differ or not exist on previous versions such as the format
function.

If you have problems accessing the sample data please contact me using
techstuffy.com.
Overview
A brief overview of the different sections contained within this book :

Section 1. Sql Server Install and Tour


This Section takes the reader from downloading and installing sql server to
creating a sql table and performing basic queries on the data within the table.

Chapter 1

This chapter introduces the book , how to use the book and where to get
downloads.

Chapter 2

Here we cover how to get a free copy of sql server express and the
installation of the software.

Chapter 3

Once sql server has been installed this chapter will take you on a brief tour of
the software and how to login to the sql server for the first time.

Section 2. Starting Sql Development


Section 2 introduces the basics of sql development namely how to create
databases, tables and fields and the fundamental statements that perform the
basic operations on your data.

Chapter 1

This chapter will show you how to create your first sql server database and
the various properties of sql server databases.

Chapter 2

Once you have created your database this chapter will explain and give
examples of creating sql server tables to store your data.

Chapter 3
In the final chapter of this section with introduce the basic sql statements to
insert, query, update and delete data from a sql table.
Section 3. Advanced Queries

Section 3 goes into sql development in more detail cover ways of grouping
data, creating conditional statements and joining tables of data together.

Chapter 1

This chapter covers how to perform calculations on groups of data such as


how to sum all the numbers in a field or count the number of rows in a table.

Chapter 2

Next we cover various functions that allow us to manipulate string fields in


various ways.

Chapter 3

Conditional statements allow us to return different values depending on the


value of another of another expression. For example you might want to return a
different value depending on the time of day or the month it ways when the
query was executed.

Chapter 4

When developing sql databases more often than not the data you need to
return will be in more than one table. This chapter covers the various ways you
can combine the data in 2 or more tables.
Section 4. Sql Beyond the Basics
Now that the basics of sql development have been covered Section 4 carries
on by introducing more development techniques such as using Stored
Procedures, Functions and Views, Triggers, database design rules and much
more.

Chapter 1

The sql developer can add rules to the check that the data being added to the
table is valid, this chapter will show you ways to create various constraints.

Chapter 2

Templates are a useful sql server feature. We will show you how to use
Templates to speed up your sql development to save you time and create
consistency and also how to create your own sql server templates.

Chapter 3

When you start to develop more complex queries you can add them to stored
procedures so that they can be saved in the database and executed with a single 1
line statement at a later date.

We will cover to create stored procedures and pass parameters to the stored
procedures.

Chapter 4

Views allow you to hide complex SELECT statements so you only need to
run a simple select statements. Using View can save you copying and pasting
large chunks of code and make it easier to read the sql that you have developed.

Chapter 5

Next we will cover different types of functions that can be created and how
they compare to stored procedures.

Chapter 6
Synonyms are aliases for tables and are especially useful when you start to
develop code that uses references to multiple databases.

We will show you how to create and manage synonyms within your
database.

Chapter 7

Triggers allow you to execute some tsql when an action is taken on the
database or table. We will cover how to create various triggers and use them for
various purposes such as auditing and preventing users from creating tables.

Chapter 8

When you start to develop sql for large amounts of data the design of the
database will be increasingly more important. We will cover the fundamental
rules of database design called normal forms.

Chapter 9

As a sql developer you can be expected to predict every possible problem


that might occur while your code is running. Sql Exceptions allow the developer
to define a course of action to take when an unexpected error occurs.

Chapter 10

Finally we cover Transactions. Transactions are the 'all or nothing' in the sql
world. You might have a number of changes to tables within your stored
procedure but want all the changes to be saved as long as there has been no
errors executing any of the statements, transactions will allow to do this.
Section 1. Sql Server Install and Tour

1. Introduction

“Knowledge isn’t power until it is applied.” – Dale Carnegie

The purpose of this book is to teach the user sql database development.

More precisely you will learn sql development on Microsoft Sql Server using
the version of Sql from Microsoft called T-SQL (T-SQL stands for Transact
SQL).

When starting to learn anything new there often appears to be an


overwhelming amount to learn.

With the Practical Series of books and 'Practical Sql' in this case you will be
guided from the basics to more advanced techniques.

The instructions are kept concise with the focus being on useful examples.
The aim here is that you will be more likely to remember what is said about a
topic and can always refer back to the examples at a later date if required.

Practical Sql
'Practical Sql' will cover the tsql development language used on the
Microsoft Sql Server Database system.

Sql Server Development is a topic that many IT Professionals avoid but there
really is no need as the basics and even more advanced techniques can be
acquired easily.

In other words Sql development is not a skill that will be of use to just DBA's
and developers.

There are many applications that rely on sql server databases so some
knowledge of databases it becoming a common requirement.
2. Sql Server Installation

The installation of Sql Server Express is straightforward, should not cause


any problems and free.

You can download the current version of Sql Server Express from the
following location:

https://www.microsoft.com/en-gb/sql-server/sql-server-editions-express

Click download now to get ‘sql server express 2017’.

System Requirements for Microsoft® SQL Server® 2017 Express

Supported Operating System

Windows 10 , Windows 8, Windows 8.1, Windows Server 2012, Windows


Server 2012 R2, Windows Server 2016

Processor

Intel - compatible processor with a minimum speed of 1 GHz or a faster


processor

RAM

Minimum 512MB

Hard Disk Space

4.2 GB of Disk Space

Limitations : Microsoft SQL Server Express supports 1 physical processor,


1 GB memory, and 10 GB storage
1. Once the download has completed double click on the file to start the
installation.
2. Click the Installation menu option on the left hand side of the screen
and then select
3. Select the Basic installation type.
1. Click Accept .

2. Click Install and wait for the installation files to be downloaded and
installed.

3. Once the installation has completed you will be presented with details
about your sql server. In particular make a note of your instance name
as this might be different from the screenshot below if you already
have a version of sql express on your machine:
4. To test your installation you can click the connect now button to
connect to the server as shown below:

5. Click Install SSMS and download the current version of the SSMS.
6. Once the download has completed, click the install and then click
install.
7. Click restart to complete the setup. Once your computer has restarted
you should be able to find the installed Sql Server Management Studio
by searching from the Start Menu:
3. Sql Server Tour
Before we get started learning sql server development we will give a brief
tour of the sql server environment itself.

This chapter will not turn you into a sql server database administrator but the
aim (especially if you are completely new to sql server) is to familiarise yourself
with some of the features, services and basic configuration of sql server.

The main sql server tool that your will be using for the configuration and
development tasks is called the 'Sql Server Management Studio' from now on
this will be referred to as SSMS.

SQL Server Services


Services are basically programs that run in the background of your computer.

The sql server runs using services, you can view these services in several
ways for example if you go to the Start Menu and search for Sql Server 2017
Configuration Manager.

Click on the Sql Server Services option and you will see the services that are
running

Sql Server (SQLEXPRESS)

The main service for sql server. You will not be able to access sql server if
this service is not running.

Sql Server Agent (SQLEXPRESS)

This service allows you to perform various tasks including the scheduling of
jobs for example to backup your sql server databases or execute tsql at a
particular time.

Sql Server Browser

The sql server browser provides information that is required when


connecting to a sql server on a server which has multiple installations of sql
server and viewing a list of available sql servers when logging onto a sql server.
To follow the examples in this book you should not need to start this service.

From the sql server configuration manager you can configure each of these
services, for example if the start automatically and the account that is used to
run the service.

The default account for the Sql Server Service is NT


Service\MSSQL$SQLEXPRESS

The account that is used to run services is important when the sql server
needs to access the filesystem for example when doing backup and restore tasks.
SQL Server Network Configuration
Within the Sql Server Network Configuration you can configure which
protocols can access your sql server.

The protocols are just different ways in which in which messages are sent to
and from your sql server installation.

The 3 protocols which we will cover next are Shared Memory, Named Pipes
and TCP/IP.

Shared Memory - default enabled

This protocol allows users running on the same computer to connect to the
sql server.

Named Pipes - default disabled

Named pipes are often used to allow applications and systems that do not use
TCP/IP to connect to the sql server

default named pipe: \\.\pipe\MSSQL$SQLEXPRESS\sql\query

To test connecting to the sql server using named pipes:

1. Right click on the 'Named Pipes' protocol and select Properties.

2. Change the pipe to:

\\.\pipe\mytest
3. Go to Sql Server Services , right click on the SQL Server and select
restart.
4. Open SSMS and select Connect - Database Engine.

Instead of the server name enter the pipe :

\\.\pipe\mytest

The reason for using named pipes is so that systems that do not use TCP/IP
can connect to your database.

TCP/IP - default disabled

This is the protocol that you will need to configure to allow your sql server
to be accessed from other machines on your network.

Protocol tab

Enabled - set this to Yes to enable the protocol.


Keep Alive (milliseconds) - This is how often the connection to the sql server
check - leave this at the default 30000 (30 seconds).
Listen All - IPAll settings used for all ip addresses (default setting).

IP Addresses tab

Used to configure the ports and individual ip addresses.

For example if you need your sql server to be accessed by another machine,
you would need to add the ip address and make sure it was set to active and
enabled, for example:
The default port for sql server is 1433, sql server express uses dynamic ports
by default

TCP Dynamic Ports - leave blank to use static ports.

When using dynamic ports the port that the sql server uses changes when sql
server restarts.

TCP Port - if you wish to set a port that doesn't change you can enter the
port in the TCP Port field. No change is required here to follow the examples in
this book.
Sql Server Properties
There are various properties of the sql server that can be set using the SSMS.

As this is a beginners guide to sql server development we will cover a few of


the useful properties you may wish to change here.

To view the properties for your sql server installation right click on the Sql
server icon in the object explorer as shown and select Properties:

On the left hand side of the 'Server Properties' dialog that is displayed you
will see that the properties are divided into the following pages:

General
The general settings display various read-only properties such as the version
of the sql server and the version of the windows operating system.

You can also display the properties such tsql commands such as the
following:

SELECT
CONVERT(sysname, SERVERPROPERTY('servername')),

SERVERPROPERTY('ProductVersion') AS ProductVersion,

SERVERPROPERTY('ProductLevel') AS ProductLevel,

SERVERPROPERTY('Edition') AS Edition,

SERVERPROPERTY('EngineEdition') AS EngineEdition,

SERVERPROPERTY('Collation') AS Collation;

The result from this query should look similar to the following screenshot:

Memory
This page shows the sql server memory options, such as the minimum and
maximum amount of memory allowed to be used by the sql server.

Security
This page allows you to set whether Sql Authentication is allowed to be used
to login to the sql server. Windows authentication mode is the default setting.

Connections
The 'Allow remote connections to this server' is the most important option on
this page, especially if you have an application running on another server that
need to access your sql server database.

Database Settings
Here is where you set the default locations for the data (the sql server
database files), Log (sql server logs) and backups:

Data

C:\Program Files\Microsoft SQL


Server\MSSQL14.SQLEXPRESS\MSSQL\DATA\

Log
C:\Program Files\Microsoft SQL
Server\MSSQL14.SQLEXPRESS\MSSQL\DATA\

Backup

C:\Program Files\Microsoft SQL


Server\MSSQL14.SQLEXPRESS\MSSQL\Backup

Advanced
There are many options on this page. The most important to note at the
moment are:

Default language - make sure this correct for your country and be aware of
the differences between English (US) and British English. The default language
setting is used when creating new logins.

Permissions
The permissions page shows the commands various logins can execute on
the server.

For now if you select the login that you used to connect to the sql server,
then select the 'Effective' tab at the bottom of the page you will see a list of
permissions which are basically a list of things that this login can do while
connected to the sql server, for example:

CREATE ANY DATABASE

Means that the login can create a sql server database.

If you select the login 'NT AUTHORITY\SYSTEM' you will see that the list
of effective permissions is more restricted that your login.

When allowing applications to connect to your sql server it is better to have


logins that are as restrictive as possible and only give the permissions they
actually require.

System databases

When you first install sql server there are 4 databases already created.
To view these 4 system databases expand the Databases folder in the Object
explorer, and then expand the 'System Databases' folder.

Next we will briefly cover the function of each of these databases.

master
Various pieces of information such as logins and configuration settings.

msdb
Backup, restore history and all details of schedules, operators and jobs.

model
Used as a template for creating new databases.

tempdb
Storage while process queries ie: sorts.

Storage area for temporary tables.

Temporary tables
Temporary tables can be used when you only require a table for a short
period of time when executing some tsql.

You can prove that the tempdb database is used to store temporary fields by
creating a table executing the following tsql:

CREATE TABLE #mytest (


test_field varchar(20)
)
The '#' in front of the table name means that it is a local temporary table.

A local temporary table can only be accessed by the session in which it was
created

If you prefix table name with '##', it is called a global temporary table which
means the table will be able to be accessed by all sessions not just the one where
the table was created.

Expand the tempdb database, then the 'Temporary tables' folder and you will
see the temporary table you have just created.

You may need to refresh the view by right clicking on the 'Temporary Tables'
folder or the tempdb database and selecting the refresh option.

If you close the query window and refresh the view again you will see the
temporary table has now disappeared.

Because the tempdb table is recreated each time the server is started you can
check the last time the sql server was restarted by right clicking on the tempdb
database, selecting properties and checking the 'Date Created' field.
First Login to Sql Server

1. Open the sql server management studio by going to the start menu and
searching for SSMS.
2. Enter the following details into the dialog box:

Server type: Database Engine

Server name: .\SQLEXPRESS

Authentication: Windows Authentication

3. Click Connect. You should now be connected to the installation of sql


server.
4. To Disconnect from sql server right click on the icon .\SQLEXPRESS
in the object explorer and select disconnect.

5. Select Connect- Database Engine from the object explorer to connect


to the sql server again.
Sql Server Log files
To check the sql server log files using the SSMS within the Object Explorer
expand the Management folder, then the SQL Server Logs and click on one of
the log files.

The most recent log file which has the prefix of 'Current' if the problem you
are investigating happened recently.

As with all systems that keep log files it is important to manage them so that
you do not run out of disk space.

If you expand the Management folder and right click on the 'SQL Server
Logs' folder and select Configure you will see the option to limit the number of
log files that are kept before they are recycled as shown. In the example below I
have set the limit of 6 log files.

Sql Server in the filesystem

1. Open windows explorer and navigate to the following folder:

C:\Program Files\Microsoft SQL Server\MSSQL14.SQLEXPRESS\MSSQL

2. Within this folder you will find the default folder for the Backup files
(Backup) and Database files (DATA).
Quiz

This is a simply quiz based on the contents of section 1. Just reading an IT


book can get boring this is why we try to keep the text concise with lots of
examples to try.

Install and Tour

Section topics - Introduction, Download and Installation of Sql Server, Sql


Server Tour.

Question 1

What is the default port that sql server uses ?

Question 2

What are the names of the 4 system databases ?

Question 3

What is the difference between "Windows Authentication" and "Sql


Authentication" ?
Section 2. Starting Sql Development
Section 2 introduces the basics of sql development namely how to:

create databases
tables and fields
fundamental statements that perform the basic operations on your data.

This is an important section to get right before moving on too quickly.

Once you are comfortable creating a database, tables and performing the
basic insert, select, update and delete statements on a table of data the following
sections should not cause any problems.
1. Create a database

1. Right click on the 'Databases' folder in the Object explorer and select
the 'New Database...' :

2. Enter a name for your database in the 'Database name' field, in this
case 'first_db'.

3. Notice as you enter the database name the logical name in the
'Database files' table is automatically generated.
4. The 2 files that will be created are called:

first_db.mdf

first_db_log.ldf

The default location of the data files is:

C:\Program Files\Microsoft SQL


Server\MSSQL14.SQLEXPRESS\MSSQL\DATA

5. Click on the Options menu item. 3 options to take note of are:

Collation - the collation settings effects the sort order , case and accent
sensitivity of the information in your tables.

Recovery Model - This option determines the type of backups that can
be performed on the database.

Compatibility level is set to SQL Server 2017(140). Setting the


Compatibility level of the database determines which tsql commands can
be used in that database.
Filegroups

The default filegroup name is PRIMARY.


Extra filegroups can be created for various uses such as :

Separating different types of data, for example data you wish to


archive.
Splitting data for very large tables.

For this book all files will be added to the default PRIMARY filegroup.

6. Click on the OK button to create the database, then you will see the
database listed under the databases folder.
2. Create Sql Tables

1. The table we are going to create will consist of the following 3 fields
and data types.

2. For each row all fields will have to be filled in.

FIELD NAME DATA TYPE

CREATED_DATEdate

CATEGORY varchar(20)

AMOUNTnumeric(5,2)

There are 2 ways that you can create this table. You can either create the
table in the gui or type in the tsql.

3. In the Management Studio expand the database you created and right
click on the Tables folder and select the Table… option.
4. Enter the Column Name , Data Type and check the tickbox if NULL
values are allowed for this field. A NULL value is an empty field.
5. A null value means that you do not have to fill in the field.
6. Once you have entered all the fields press Ctrl+S to save the table and
enter a table name of spending_initial.
Create the table using tsql

1. To create the table using tsql click on the 'New Query' button in the
toolbar or press Ctrl+N to open a new query window.
2. Enter the text below and press Alt+X or the Execute button in the
toolbar to execute the statement.
use first_db

CREATE TABLE [dbo].[spending_initial](

[created_date] [date] NOT NULL,

[category] [varchar](20) NOT NULL,

[amount] [numeric](5,2) NOT NULL

3. In the tsql about the USE statement changes the database to first_db.
If you have called your database a different name you will need to
change it here.
4. The CREATE TABLE statement consists of the table name in the
format:

schema.tablename

The default schema is 'dbo'.

Schemas are used to group objects such as tables and views. In this book we
will always be using the dbo schema.

5. Next within brackets are a list of the fields in the table.

The three fields we have created are :

(The 'NOT NULL' option means that when creating a row you need to enter
a value in each field, otherwise you would just enter the text 'NULL')

6. Create a field called created_date with a data type of date:

[created_date] [date] NOT NULL


Create a field called category where each field will contain a string of 20
characters or less:

[category] [varchar](20) NOT NULL

Create field called amount which is the numeric , the value will have 5 digits
in total with 2 after the decimal point, for example 123.45 :

[amount] [numeric](5,2) NOT NULL

7. When you execute the statement the following message will be


returned if there are no errors:
Commands completed successfully.
8. Right click on the Tables folder in the Object explorer and select
Refresh to see the table you have just created, for example:

9. If you need to remove a table from your database you can either right
click on the table and select the Delete option, then click OK to
confirm the deletion or run the follow DROP command:

DROP TABLE <your table name>


10. Next we will look at creating the basic queries to insert, update and
delete rows in this table.
Convert - your data
Sometimes you need to change the data type of an expression.
The CONVERT function is useful also for changing the format of the date\time
field using predefined codes for different formats of date fields.

1. Next we will cover how you can use the CONVERT function to
change expressions such as a datetime returned from a GETDATE()
function into a varchar data type.
2. The format for the CONVERT function is:

CONVERT ( data_type , field_to_convert, code )


date_type = this is the target data type ie: varchar(32).

field_to_convert = the field you want to convert ie: GETDATE().

code = an optional parameter to set a predefined style.

Some examples of styles you can use:

Default date format if no code parameter is used:

mon dd yyyy hh:miAM (or PM)

US

1 = mm/dd/yy

101 = mm/dd/yyyy

10 = mm-dd-yy

110 = mm-dd-yyyy

British/French
3 = dd/mm/yy

103 = dd/mm/yyyy

German

4 = dd.mm.yy

104 = dd.mm.yyyy

If you cannot find the style you require for your country or the format for the
date you require listed here you can find the full list of codes here:

http://technet.microsoft.com/en-us/library/ms187928.aspx

3. Execute the following CONVERT to see how changing the code


parameter changes the result returned:

British date format example, the result is: 14/04/2019


4. select CONVERT(varchar(10), GETDATE(), 103)

US date format example, the result is: 04/14/2019

select CONVERT(varchar(10), GETDATE(), 101)

If you omit the code parameter the field will be returned using the
default date format. Note we have increased the length of the data type we
are using so that the full datetime field is displayed:

select CONVERT(varchar(20), GETDATE())


The result is: Apr 14 2019 11:50AM
Format - your data

The format command returns a formatted result based on the format string
and optional culture parameter that is passed to it.

The format command is only available on sql server from version 2012, if
you try to run this command on previous versions of sql server you will get the
following error:
Msg 195, Level 15, State 10, Line 1
'format' is not a recognized built-in function name.

It is important to remember this just in case there is the possibility that the
code you are developing will at some point run on a previous version of sql
server such as sql server 2008 R2.

Obviously you will not have this problem while learning using 1 sql server
but might encounter it when you start using sql server in a company.

The syntax of the FORMAT function is:

FORMAT ( Expression,Format_to_return[ ,Culture])

Expression = this is the value that needs to be formatted, ie: GETDATE().

Format_to_return = the format_to_return parameter is either a predefined


code such as:

N - Numeric

G - General

C - Currency

Or a format that the users passes for example to format a date string ‘dd-
MM-yy’.

Culture = optional parameter, example of cultures are :

'en-US'= US English
'en-gb'= British English

'de-de' = German
This option defaults to the current language of the session. Next we will
cover an example of how to use the format function.

1. Execute the following statement using the format function:

select format(getdate(),'dd-MM-yy','en-gb')

You should get a result returned in this format (obviously the date will
be different)

14-04-19

Some other fields that you can use for format string when using dates
are:

Code Format
MM Month Number 01-12
MMM Short Month ie: Jan,Feb etc…
ss\s Second
t AM\PM
yy\yyyy Year
Mm Minute
hh 12 hour
HH 24 hour
dd Day
ddd Short day ie: Mon,Tue,Wed etc…
dddd Full name of day

When working with dates the first thing you need to check is that you are
using the correct date format for your country.

You can see a list of the possible languages available on your system using
the following statement: select * from syslanguages
Get the current DATEFORMAT
The DATEFORMAT setting will determine the default format for dates.

1. Execute the following command :

DBCC USEROPTIONS

2. A number of rows will be returned, if you look at the row where the
‘Set Option’ field is ‘dateformat’ you will see the current dateformat
setting,for example it might be:

mdy

This defines the order as month day then year. You can change the
dateformat setting using the ‘set dateformat’ command.

For example if you wanted to change the order of the day and month so
that the day is first you would use the following command:
set dateformat dmy

3. Open a 'New Query' window and check the dateformat using the
DBCC USEROPTIONS command.
4. You will see it is mdy and the dateformat does not change for all
sessions.
5. If you change the default language of the login that date format will
change for all sessions.
6. Open the security folder, logins , right click on your login and select
properties.
7. Select the General option on the left side of the dialog and change the
Default Language to British English or English if it is already set to
‘British English’.
8. Open a new query window and execute the DBCC USEROPTIONS
command. You will see the following settings have changed:
languageBritish

dateformatdmy

Set the default language back to English:

languageus_english

dateformatmdy

Date functions
In some way or another most tables you will be developing will probably
have a date field, for example the date\time field is often used to show when the
row was created.

Next we will cover the more useful date functions that are available on sql
server.

GETDATE

The GETDATE function simply returns the current date\time in the


following default format:

YYYY-MM-DD hh:mm:ss[.nnn]

For example:
select GETDATE()

Will return something in the following format:

2019-04-14 12:00:12.510

CAST
Format: CAST(<expression> as <data type>)

Here are 2 examples of using the CAST function to either return just the date
or time from the GETDATE function.
The default format of the date data type is YYYY-MM-DD, execute the
following statement:
select cast(GETDATE() as date)

The result should be:

2019-04-14

The default format of the time data type is hh:mm:ss[.nnnnnnn] , execute the
following statement:

select cast(GETDATE() as time)

The result should be: 12:01:11.6600000

DATEPART

With the DATEPART function you can obtain certain parts of the datetime
field returned from the GETDATE function .

The format of the DATEPART function is:

DATEPART(<part_of_date>,date_expression)

< part_of_date > = a keyword representing the part of the date you require
for example using DAY , MONTH, or YEAR returns the different parts of the
date as you would expect.

Date_expression = the expression containing the date ie: GETDATE


function.

The following statement returns the number of the current month ie: 4 for
April:
select DATEPART(month,GETDATE())

Instead of month we could have returned other parts of the date such as:

DAYMONTHWEEKDAY

YEARHOUR

MINUTESECOND

Using the weekday for the first parameter returns the number for the day of
the week, eg:
select DATEPART(weekday,GETDATE())

DATENAME

Format: DATENAME(<part_of_date>,date_expression)

The DATENAME function returns the string values of the part of the date
you require.

For example the following statement will return the word ‘August’ for the
current month instead of 8 (that would be returned by the DATEPART function).
select DATENAME(month,GETDATE())

The weekday option for the first parameter returns the name of the day such
as Monday, Tuesday etc…
select DATENAME(weekday,GETDATE())

Create Fields
A table in a database consists of rows and columns much like a spreadsheet.

9. Each column represents a field.


Each row in the table represents a value in each of the fields.

To setup a table you need to set the data type of each field. The data type is
used to tell sql server what kind of information to expect such as a string of 10
characters in length, numeric value or a date.

Next we will create a simple table to store the amount of money spent on
different categories and the Month the money was spent. The 3 fields used will
be:

MONTH, CATEGORY and AMOUNT

The 3 different data types we will use are char, varchar and money.

char\varchar

A char data type represents a fixed string value.

For example a data type of char(3) will always use 3 characters even if
the string is less than 3 characters.

varchar data type stands for variable character and means it will only
use the amount of space it requires depending on the length of the string.

nchar\nvarchar as the unicode version of the char\varchar data types.

Unicode data can represents a wider range of characters for example


when using a Japanese alphabet.

Most of the time using char\varchar will be fine unless you are
developing for international users.

3. Sql Queries

Query the table

Most of the queries in sql development are based around the following 4
types of queries.
Insert - putting data into the table
Select - reading data from the table
Update - updating the rows in the table
Delete - deleting some or all the rows from the table

Once you have a good understanding of the basic version of these


commands you have a good foundation for the sql development knowledge
as the more complex queries are only variations of the basic queries we will
cover next.

I would not continue with the other examples until the commands
presented in this chapter are clear and you are happy to execute simple
insert, select, update and delete commands without referring to the book.
INSERT Statement
This needs to be the first statement we cover as we need to put data into the
table before we can read, update or delete that data.

Using SSMS

1. Right click on the table dbo. spending_initial and select the option
'Edit Top 200 Rows'.

2. Press the tab buttons to move between fields. When you press the tab
button from the last field another row will be added. Enter the
following rows:

Insert using TSQL

1. The basic format of the INSERT statement is:

INSERT INTO <table name> ([list of fields]) VALUES (<list of


values for fields>)
2. For example:

USE [first_db]

GO

INSERT INTO [dbo].[spending_initial]


([created_date],[category],[amount])

VALUES ('1/9/13','OTHER','15.20')

GO

(1 row(s) affected)

3. If you are entering all the fields into the table you do not need to list
the fields after the table name, for example:

INSERT INTO [dbo].[spending_initial]

VALUES

('10/8/13','OTHER','10.20')

GO

Next we will cover how you can perform queries on the data in your table.
SELECT Statement

4. To get data out of the table you need to use a SELECT statement

Using SSMS

1. Right click on the statement and select the option Select Top 1000
Rows.

2. The following command will be displayed in a new query window and


executed:

/****** Script for SelectTopNRows command from SSMS ******/

SELECT TOP 1000 [created_date]

,[category]

,[amount]

FROM [first_db].[dbo].[spending_initial]

3. The results are from the data in my table are:


Using Tsql

Run the following simple select statement:

Select * from [first_db].[dbo].[spending_initial]

4. This will display the same results as the command generated by the
gui.
5. The '*' represents all the fields in the table or you can list the fields you
wish to return for example:

SELECT [created_date],[category],[amount]

FROM [first_db].[dbo].[spending_initial]

6. If you only wanted to display each of the unique categories in the table
you can put the DISTINCT keyword before the fieldname as shown:

SELECT DISTINCT [category]

FROM [first_db].[dbo].[spending_initial]

7. If you have a table with a large number of fields you can restrict the
number of rows returned using the TOP keyword, for example to
return only 3 rows you would use the following SELECT statement:
SELECT TOP 3 * from spending_initial
8. To specify the ORDER in which the rows are returned you use the
ORDER BY clause which passes a list of 1+ fields so set the order, for
example to return the fields ordered by category and then amount you
would use the following statement:
SELECT TOP 3 * from spending_initial
ORDER BY category,amount
9. By default the ORDER BY clause orders the fields as ascending, if
you would like to reverse the order so that the rows are descending
(sometimes useful for dates so the newest rows are at the top) you
would use the following statement to see the top 3 rows ordered by the
created_date field in descending sequence:
SELECT TOP 3 * from spending_initial
ORDER BY created_date DESC
10. If you wanted to list all the rows where the category had a certain
string of characters in the category you would use the LIKE keyword
in the WHERE clause.
You can use the % symbol to represent ! or more characters.

For example the following statement will return all rows where the
category contains 'COF' , which will probably only be the rows for
COFFEE.

SELECT * from spending_initial


WHERE category like '%COF%'
11. If you wanted to use a WHERE clause where the category started with
'L' you could use the following statement and leave out the first %
symbol, for example:

SELECT * from spending_initial


WHERE category like 'L%'

12. You can backup your table of data before experimenting with changes
using the SELECT INTO statement:
The format is :

SELECT <field list> INTO <new tablename> FROM <table to backup>

13. The following statement will make a backup of the spending_initial


table into a table called mybackuptable:
SELECT * INTO mybackuptable from spending_initial
UPDATE Statement
Now that we have some data in the table we will cover how to update fields
in the table.

If you have a small table you can easily edit the data using the SSMS
gui in the same way you used to insert the data. If you have a very large
table or need to update many rows you will need to use the tsql UPDATE
statement.

Using SSMS

1. Right click on the spending_initial table and select 'Edit Top 200
Rows'.

2. Here you can change the data in the field and it will be saved once you
select a field in another row by using the mouse or pressing the tab key
until the cursor moves to another row.
3. Next we will cover how to update rows in the table using the tsql
UPDATE statement.
4. For basic format of the UPDATE statement is:

UPDATE <table name>

SET <fieldname> = <new value>

WHERE <fieldname>=<value>

For example if we wanted to change the CATEGORY called LUNCH to


FOOD :

5. Click the 'New Query' button and choose the first_db database from
the dropdownlist.
6. Enter and execute the following tsql statement to change all the fields
that have a CATEGORY of LUNCH to FOOD :
UPDATE [spending_initial]

SET category='FOOD'

WHERE category='LUNCH'

7. In this example we have added a WHERE clause.


8. The WHERE clause it used to only apply the UPDATE statement to a
selection of rows in the table. In this example the WHERE clause
(WHERE category='LUNCH') means that only the rows that have a category
field set to 'FOOD' will have their category changed to 'LUNCH'.
9. If we did not include the WHERE clause all the rows in the table
would have their category field set to 'FOOD'.
10. The result is:
(2 row(s) affected)

11. Execute the following tsql SELECT statement to check the results of
the UPDATE statement:

select * from [spending_initial]


DELETE statement
We have covered the basic forms of the INSERT, SELECT and UPDATE
statements. Now we will conclude this chapter by covering the DELETE
statement.

The DELETE statement is used to remove rows from the table.

Using SSMS

1. Right click on the table dbo.spending_initial and select the option 'Edit
Top 200 Rows'.

2. Select the row using the column to the left of the first column as
indicated in the next screenshot:

3. Press the delete key and the following warning will appear

4. Click the Yes button to delete the row.


Using TSQL

The format of the DELETE statement is :

DELETE FROM <table>

[WHERE field=value]

If a WHERE clause is not included all the rows will be deleted from the
table.

1. Click the 'New Query' button and choose the first_db database from
the dropdown list.

2. Enter and execute the following tsql statement to DELETE the rows
where the category is set to OTHER.

DELETE FROM [spending_initial]

WHERE category='OTHER'

3. After the command has executed successfully you can run a simple
tsql select statement to confirm that the rows have been deleted :

select * from [spending_initial]


Quiz

Starting Sql Development

Section topics include - Creating Database, Tables and Fields and first sql
queries.

Question 1

What command is used to delete a table using t-sql ?

Question 2

What is the difference between nvarchar and varchar data types ?

Question 3

What command is used to find the current dateformat ?


Section 3. Advanced Queries
In Section 3 of this book we will continue by covering various topics used in
sql development such as how to :

1. Group Data
2. Manipulate strings
3. Total numeric fields in a table
4. Creating various sql database objects

such as stored procedures, functions, triggers and views.


1. Grouping data
Next we will look at how you can group your data.

For example still using the previous spending data you might want to total
the amount you have spent in each of the different categories.

To group data you use the GROUP BY clause and aggregation functions.

Aggregation functions

An aggregation function performs a calculation on a set of fields. For


example SUM() totals the values in the field.

If you use an aggregation function without any GROUP BY clause you will
get the total for the whole table, for example:
SELECT sum(amount)

FROM [first_db].[dbo].[spending_initial]

SUM

The sum function is one of the most common aggregation functions used and
simply totals the values in the field specified within the function.

In the example below we have added a header to the result by adding the
alias 'as' <alias name> :
Using the 'as' keyword in this way can also be used to change field names.
SELECT sum(amount) as spending_total

FROM [first_db].[dbo].[spending_initial]
COUNT

The COUNT function simply returns the number of rows in the data.

The parameter in the count function can either be a fieldname or '*' which
will count all the rows in the table.

For example:
select count(*) as count

from [first_db].[dbo].[spending_initial]

and
select count(category) as count

from [first_db].[dbo].[spending_initial]

Will both return a result of 4.

COUNT DISTINCT

The COUNT( DISTINCT <fieldname>) function will count all the unique
values that are not null.
select count( distinct category) as count

from [first_db].[dbo].[spending_initial]

Will return a result of 2, because there are only 2 unique categories in the
sample data we are using( COFFEE and FOOD).

MIN\MAX

These functions find the minimum\maximum values as you might expect.


You can use them with strings as well such as char\varchar where they will
find the minimum\maximum in the sort sequence.

select max(amount) as count

from [first_db].[dbo].[spending_initial]

Will return a value of 3.29

Whereas the following statement will return a result of 'COFFEE', because


when sorted COFFEE comes before FOOD :
select min(category) as count

from [first_db].[dbo].[spending_initial]

AVG

The AVG function will return the average of the values in the fields.

For example:
select avg(amount)

from [first_db].[dbo].[spending_initial]

Will return a result of 2.697500.

This is the sum of the 4 values in the table:

2.25
3.29
2.25
3.00

Which is 10.79/4 = 2.6975

Use can use the DISTINCT keyword with the avg function, for example:
select avg(distinct amount)

from [first_db].[dbo].[spending_initial]

This will return a value of 2.846666.

3.29
2.25
3.00

The total is 8.54/3 = 2.846666.

GROUP BY

Using the GROUP BY clause you can summarize your data which can help
you gain a better understanding of your data, this is useful for reports and
especially when you have a large amount of data you are working with.

The GROUP BY statement allows you to perform aggregation functions on


each unique value in the specified field list.

Fields in the SELECT field list that are not aggregate functions need to be in
the GROUP BY field list.

For example:
SELECT sum(amount) as spending_total

FROM [first_db].[dbo].[spending_initial]

GROUP BY category

will return:

You can add the fields in the GROUP BY list to the fields in the SELECT
statement to make it obvious which value applies to which CATEGORY.
SELECT sum(amount) as spending_total,category

FROM [first_db].[dbo].[spending_initial]

GROUP BY category

will return:

The fields listed in the select statement need to be either in the GROUP BY
clause or an aggregation function.

Filtering Aggregation Functions

The HAVING clause is used with GROUP BY much like the WHERE clause
but instead of being applied to single rows in a table is applies to the result of the
aggregation functions.

SELECT sum(amount) as spending_total,category

FROM [first_db].[dbo].[spending_initial]

GROUP BY category

HAVING sum(amount)>5

The result of this statement is:

If you do not use an aggregation function in the HAVING clause such as:
SELECT sum(amount) as spending_total,category

FROM [first_db].[dbo].[spending_initial]

GROUP BY category
HAVING amount>5

You will get the following error:


Msg 8121, Level 16, State 1, Line 4

Column 'first_db.dbo.spending_initial.amount ' is invalid in the HAVING clause because it is not


contained in either an aggregate function or the GROUP BY clause.

2. Strings
There are several functions in sql development that deal with the
manipulation of strings.

Next we will cover the main examples of string functions that allow us to
perform various functions such as:

Removing blank spaces before and after the string.


Finding out the length of the string
Extracting only part of the string
Finding the position of a character within the string

The functions we will cover here are:

LEN

CHARINDEX

LEFT \ RIGHT

SUBSTRING

LTRIM\RTRIM

UPPER\LOWER

CONCAT

REPLACE

The examples we will cover show examples of the functions as used in the
SELECT statement but you can also use the functions anywhere a string value
would be required, for example in a WHERE clause, UPDATE or DELETE
statement.
LEN
FORMAT: LEN(<expression>)

The LEN function returns the number of characters in an expression for


example a string \ numeric field.
select len(category) as len ,category

from [first_db].[dbo].[spending_initial]

GROUP BY category

This query returns the length of each category field as shown:

The LEN function can be applied to numeric as well as string fields.

CHARINDEX
FORMAT: CHARINDEX(stringtofind,stringtosearch,[startlocation]))

stringtofind - This is the string\expression that you are looking for.


stringtosearch - this is the string that is being searched.
startlocation - an optional starting index,0=beginning of string.

The CHARINDEX function returns the position of a string wthin another


string.

This example searches for the letter 'o' in the category fields:

select charindex('o',category) as char_index, category

from [first_db].[dbo].[spending_initial]

GROUP BY category
The result is the index of the first occurrence of the letter 'o' in each of the
category fields.

The next example adds the third optional parameter of the starting location.

In this example we are starting at the 3rd character.


select charindex('o',category,3) as char_index, category

from [first_db].[dbo].[spending_initial]

GROUP BY category

The result from this statement is that the COFFEE category returns a result
of 0 because there is no letter 'o' from the 3rd character, whereas the category
FOOD returns a charindex of 3 because the 3rd character is the letter 'o'.

LEFT \ RIGHT
FORMAT: LEFT(Expression,num_of_chars)\
RIGHT(Expression,num_of_chars)

The LEFT \ RIGHT functions are similar and return a number of characters
starting on the left or right side of the string.

For example:
select left(category,3) as read_left, category

from [first_db].[dbo].[spending_initial]

GROUP BY category

Would return:
whereas using the right function instead such as the following statement:
select right(category,3) as read_right, category

from [first_db].[dbo].[spending_initial]

GROUP BY category

would return the result:

You can use the left and right functions on numeric values as well as strings.

SUBSTRING

FORMAT: SUBSTRING(expression,start location,number of characters


to read)

The SUBSTRING function allows you to extract part of an expression


(normally a string field).

The 3 parameters are :

The expression - such as a field name,function or string.

The start location - The number of characters - starting from the left side of
the string.

The number of characters to read.


select substring(category,2,3) as read_middle, category

from [first_db].[dbo].[spending_initial]

GROUP BY category

In this example we have extracted 3 characters from the category field


starting at the second character from the left side of each field. For example for
the COFFEE category we start at the second character which is 'O' and returns
the 3 characters from the 'O' which returns 'OFF'.

Combining functions

The charindex is useful for reading all the characters in a string up to a


certain character.

For example:

If you wanted to read all the characters in each category from the left until
the first 'o' you could use the following statement:

select left(category,charindex('o',category)-1) as read_left, category

from [first_db].[dbo].[spending_initial]

GROUP BY category

This statement combines the left and charindex. We have subtracted 1 from
the result returned by the charindex function so that the string returned by the
left function does not include the letter 'o':
charindex('o',category)-1
LTRIM\RTRIM

FORMAT: LTRIM\RTRIM(expression)

Sometimes when you read a string from a database there might be spaces
after the string that can cause problems in certain scenarios such as comparing 2
strings or inserting data into smaller fields.

For example 'my teststring ' would not be equal to 'my teststring'.

Also, you would not be able to insert the field 'my teststring ' into a field of
char(13) because the string is actually 14 characters long (13 characters + 1
space) so this would cause an error.

To get around this problem you can remove the spaces before and after the
string.

The most common function to use is RTRIM which removes whitespaces


from the right side of the string:

Instead of using the LEN function we will use the DATALENGTH function
which return the length of the string in bytes, the reason for this is that the LEN
function ignores trailing whitespace whereas the DATELENGTH function does
not.

The following example returns a value of: 15


select DATALENGTH(' my teststring ') as result

Using the LTRIM function

The following example returns a value of: 14


select DATALENGTH(LTRIM(' my teststring ')) as result

This is because it removes the space from the left side of the string.
Using both LTRIM and RTRIM

The following example returns a value of: 13


select DATALENGTH(RTRIM(LTRIM(' my teststring '))) as result

This is because the spaces on each side of the string have been removed.

The problem with whitespaces is that you cannot see them in the results
returned in the SSMS so you might not initially realize you have a problem with
whitespaces.
UPPER\LOWER

The upper and lower functions convert the string into upper or lower case.

The following statement returns the value: MARK


select UPPER('MaRk')

Whereas, the LOWER function below will return a value of: mark.
select LOWER('MaRk')

These functions are often used when comparing fields so that you can make
a comparison regardless of differences in the case of the strings.
CONCAT

The CONCAT function combines the strings in the parameter list into 1
string.

FORMAT:
CONCAT(string1..n)

This statement would return a result of:My name is mark


select CONCAT('My ','name ', 'is ', 'mark')

Use can use the '+' character to concatenate strings and get the same result as
the previous example: select 'My '+'name '+ 'is '+ 'mark'

REPLACE

The REPLACE function allows you to perform a simple search and replace
on strings.

FORMAT:
REPLACE(expression to use, string to find, string to replace with)

The REPLACE function is commonly used to make changes such as:

1. Changing the direction of '/' characters to '\'.

2. Changing strings like pathnames\servernames in strings.


3. Removing whitespace from within the string or converting whitespace
to a character.

For example:
In this simple example we will replace the 'O' characters in each of the
category fields with 'o':
select REPLACE(category,'O','o') as replace_string, category

from [first_db].[dbo].[spending_initial]

GROUP BY category

The result of this statement is :

You can see that the replace function has replaced all the occurrences of 'O'
to 'o' so the FOOD category has been changed to FooD.
3. Conditional statements
In sql development conditional statements allow you to make changes based
on the values of other expressions.

For example: You might want to return 'Good Morning' if the time is before
12AM or 'Good Afternoon' if is after 12AM.

In this chapter we will cover 2 conditional statements, these are the IF


statement and the CASE statement.

The case statement is used within field lists such as SELECT statements
whereas the IF statement can be used on its own as we will see in the next
example or within stored procedures.

IF Statement

FORMAT:

IF <some expression which is true\false>

BEGIN

<execute some statements>

END

NOTE: The BEGIN and END statements are only required if there are more
than 1 statements to be executed, but it is good practice to include them anyway
in case you need to add more statements later on.

This example will get the current hour and if the value is greater than 12 it
will display the message 'Good Afternoon'.

The PRINT statement is used to display a message to the user.


IF ( SELECT DATEPART(hour,GETDATE()) )>12

BEGIN
PRINT 'Good Afternoon'

END

IF...THEN...ELSE

FORMAT

IF <some expression which is true\false>

BEGIN

<execute some statements>

END

ELSE

BEGIN

<execute some other statements>

END

If the first IF statement does not evaluate to TRUE then the statements in the
ELSE part of the statement will be executed.

For example:
IF (SELECT DATEPART(hour,GETDATE()))>12

BEGIN

PRINT 'Good Afternoon'

END

ELSE

BEGIN

PRINT 'Good Morning'


END

Case Statement

FORMAT:

SELECT

(CASE

WHEN <expression to evaluate>

THEN <set value of the field>

END) as <fieldname>

FROM <some table>

The case statement if commonly used within select statements to return


different values for a field depending on some condition.

An example of a CASE:
SELECT

(CASE

WHEN DATEPART(hour,GETDATE()) > 12

THEN

'Good Afternoon'

END) as current_message

The difference here to the IF statement is that instead of a message that is


printed to the user the result is returned in the same way as a select statement
returns the rows of a table.
As with the IF statement you can have multiple conditions in the case
statement, for example:
SELECT

(CASE

WHEN DATEPART(hour,GETDATE()) > 12

THEN

'Good Afternoon'

WHEN DATEPART(hour,GETDATE()) > 6

THEN

'Good Morning'

ELSE

'You should be asleep'

END) as current_message

In this example we have added another WHEN clause to display 'Good


Morning' when the hour is greater than 6.

The message 'You should be asleep' is displayed when none of the conditions in
the WHEN clauses are satisfied. In this case the ELSE clause will be used when
the current hour is not greater than 6 or 12.
4. Joining Tables
Next we will cover 2 different ways to combine the data in 2 tables.

1. JOINS - joins are used to add the fields in 2 different tables together in
different ways.

For example in one type of join you might have the following 2 tables:

TABLE A fields:

a1

a2

TABLE B fields:

b3

b4

In this case you might want to perform a select statement that returns
the fields:

a1, a2, b3, b4.

The rows that are returned in this dataset depend on the type of join
used.

2. COMBINING the rows of 2 datasets.

In this case the columns in each dataset need to be the same.

The rows in the 2 datasets will be combined and returned to the user.

The keywords we will be using are:

UNION,EXCEPT,INTERSECT
Sample data for joins
For these examples to join and combine data from 2 tables we will need to
create another table with some sample data.

1. In this scenario we are going to create a table called spending_users.


The spending_users will contain a list of users, their department within
the company such as IT or Sales, and a field called budget which will
be used as a limit for the amount of spending.

CREATE TABLE [dbo].[spending_users](

[user_id] [int] NOT NULL,

[firstname] [varchar](20) NOT NULL,

[lastname] [varchar](20) NOT NULL,

[department] [varchar](50) NOT NULL,

[budget] [numeric](5, 2) NOT NULL

2. Add a field to the [dbo].[spending_initial] table. To do this right click on the


table and select design.
3. Add the field user_id with a data type of int, leave the tick in the
'Allow Nulls' box.
4. Next we will add some sample data using the following tsql:

INSERT INTO [dbo].[spending_users]

([user_id],[firstname],[lastname],[department],[budget])

VALUES

(1,'Joe','Blogs','Sales',100)

GO
5. Change the values in the tsql to insert more rows of data. The
spending_users sample data should look like the following table:

6.
7. Finally edit the [spending_initial] table and update the user_id field to
correspond to one of the user_id fields in the spending_users table, in
this example that will be 1,2 or 3.
8. The user_id fields will be used to join the 2 tables in different ways in
the following examples. The spending_initial table should look like
the following screenshot:
Join Types

Table joins allow you to combine columns of data from different tables.

In the following examples we will cover the different types of joins that can
be performed.

INNER JOINS

FORMAT:

SELECT <some fields>

FROM <first table>

INNER JOIN <second table>

ON <first table field>=<second table field>

INNER JOIN will only display records where there is a matching record in
each table, all other rows will be excluded from the final table.

For example:

1. Add another row to the table [spending_users] with a user_id of 4.

2. Make sure there are no rows in the table [spending_initial] with a user_id
of 4.
3. In this example we use '*' for the field list in the select statement to
return all the fields from both tables.

SELECT *

FROM [first_db].[dbo].[spending_initial]

INNER JOIN [dbo].[spending_users]

ON [spending_initial].user_id = [spending_users].user_id

4. As you can see from this example all the fields from the
spending_inital and spending_users tables are listed where there is a
match between the user_id fields.

After the SELECT statement there is the INNER JOIN keyword then
the table which you wish to join to the table in the SELECT statement for
example:
INNER JOIN [dbo].[spending_users]

5. The ON keyword is then used to specify the 2 fields that should match
in order for the row to be included in the final table.
6. In this example we are using the user_id field to match rows in the 2
tables although the fields do not have to have the same name.
7. INNER JOIN keyword is the same as using the JOIN keyword.

TABLE ALIASES

To save on typing you can add tables aliases to this query that allow you to
refer to the table by a different name (normally a shorter name if you have any
sense), for example:
SELECT *

FROM [first_db].[dbo].[spending_initial] spent

INNER JOIN [dbo].[spending_users] users

ON spent.user_id = users.user_id

You can see that no keyword is required after the table name to give the table
an alias (unlike the field field alias used in the SELECT statement which uses
the 'as' keyword).
OUTER JOINS

An outer join allows rows that do not match to still be included in the final
table of the select statement.

The ‘outer join’ will combine all rows from both tables whether they are
matching or not.

Using our previous example we can change the query to an OUTER JOIN

When joining tables together the first table that is part of the SELECT
statement is also known as the left table, whereas the second table used is known
as the right table. In this example:

LEFT TABLE = spending_initial

RIGHT TABLE = spending_users

This distinction between the left and right tables is not that important with
INNER JOINS but becomes more important when using LEFT and RIGHT
OUTER JOINS.

LEFT OUTER JOIN

First we will look at the left outer join.

Using the example from the inner join example simply change the keyword
'INNER JOIN' to 'LEFT OUTER JOIN' as showing the example :
SELECT *
FROM [first_db].[dbo].[spending_initial] spent
LEFT OUTER JOIN [dbo].[spending_users] users
ON spent.user_id = users.user_id

The result of this query is:


You can see that all the rows from the left table(spending_inital) have been
included and only matching rows from the right table(spending_users).

If you change the order in which the tables are used in the statement so that
the spending_users table becomes the first table (LEFT TABLE) that is used in
the SELECT statement and the spending_inital table is used after the 'LEFT
OUTER JOIN' keyword.

In this example all the rows are included from the list of users
(spending_users) whether or not there are matching rows in the spending_initial
(RIGHT TABLE).
SELECT *
FROM [dbo].[spending_users] users
LEFT OUTER JOIN [first_db].[dbo].[spending_initial] spent
ON spent.user_id = users.user_id

The result of this query is:

You can see that the 5th row of this table includes the user details for the
user_id of 4 , but NULL values for all the fields from the spending_initial table.
The reason for the NULL values is that there are no rows in the spending_initial
(RIGHT TABLE) that have a user_id of 4.

Also note, there are 2 rows with a user_id of 1. The reason for this is that
there are 2 rows in the spending_initial table that have a user_id of 1.

You can replace the keyword 'LEFT OUTER JOIN' with 'LEFT JOIN' and
you will get the same result.
SELECT *
FROM [dbo].[spending_users] users
LEFT JOIN [first_db].[dbo].[spending_initial] spent
ON spent.user_id = users.user_id
RIGHT JOIN

A right outer join is simply the opposite of a left outer join, where all the
rows of the right table are listed in the final table.

In the LEFT OUTER JOIN examples, when we swapped LEFT and RIGHT
tables around we could have just changed the 'LEFT OUTER JOIN' to a 'RIGHT
OUTER JOIN' and we would have achieved the same result. The only
difference would have been the ordering of the fields returned.

For example:
SELECT *

FROM [first_db].[dbo].[spending_initial] spent

RIGHT OUTER JOIN [dbo].[spending_users] users

ON spent.user_id = users.user_id

The result of this query is:

You will notice that the order of the fields returned changes when you
change this query from a 'LEFT OUTER JOIN' to a 'RIGHT OUTER JOIN'.

You can replace the keyword 'RIGHT OUTER JOIN' with 'RIGHT JOIN'
and you will get the same result:

SELECT *

FROM [first_db].[dbo].[spending_initial] spent

RIGHT JOIN [dbo].[spending_users] users

ON spent.user_id = users.user_id
FULL JOIN

The FULL OUTER JOIN returns a combination of all rows from both fields.

1. Edit the spending_initial table and change one of the rows that has a
user_id of 1 to 6.

2. The reason for this is that the user_id of 6 doesn't exist in the
spending_users table so it will demonstrate that all the rows from both
fields are included in a FULL OUTER JOIN.
3. When you edit the spending_initial table the table should look
something like from the following screenshot:

4. Now when you change the join in our statement to 'FULL OUTER
JOIN' as the following text:

SELECT *

FROM [first_db].[dbo].[spending_initial] spent

FULL OUTER JOIN [dbo].[spending_users] users

ON spent.user_id = users.user_id

5. You will get the result:

6.
7. You can see that the first row of this table is for user_id 6, this row has
null values for the fields that are from the spending_users table.
8. Other the hand the last row in this table which is for user_id 4, has null
values for the fields from the spending_initial table because no rows
exist in the spending_initial table for user_id 4.
Cross join - Cartesian product
The cross join is very inefficient and should really be avoided as it can cause
performance problems on your sql server when using large tables.

But we will demonstrate it will our sample data.

The cross join combines every row in the first table with every row in the
second table.

We have 4 rows in each of the tables used in the following statement the
result has 16 rows.

SELECT * FROM [first_db].[dbo].[spending_initial] spent


CROSS JOIN [dbo].[spending_users] users

The result of the CROSS JOIN is:


Multiple Joins

You can join multiple join statements together but for performance reasons it
is best to limit these for 4\5 joins especially for larger tables.

You create a statement with multiple joins by just appending one join clause
after another.
SELECT * FROM [first_db].[dbo].[spending_initial] spent

RIGHT JOIN [dbo].[spending_users] users

ON spent.user_id = users.user_id

LEFT JOIN [dbo].[another_table] another

ON another.user_id = users.user_id
Combining Rows
The 3 keywords used for combining rows we will be covering next are
UNION,EXCEPT,INTERSECT.

These allow you to combine the rows in 2 tables.

Sample data

In this example we are going to be combining spending data in 2 tables.

1. We need to setup another table that contains spending data. Execute


the following tsql to create another spending table:

CREATE TABLE [dbo].[spending_more](

[created_date] [date] NOT NULL,

[category] [varchar](20) NOT NULL,

[amount] [numeric](5, 2) NOT NULL,

[user_id] [int] NULL

2. Add the following data to your table:

3. Notice that the second row added is the same as one of the rows in the
spending_initial table, the reason for this is so that we can demonstrate
when duplicate rows are allowed or not.
UNION

Before you can combine the data in 2 tables check that the fields are in the
same order, and the field data types are either the same (best practise) or are
similar enough so they are automatically converted, this is called implicit
conversion.

An example of implicit conversion is converting between char and varchar


values when you read the values from one field that has a data type or char and
insert them into another field in another table that has a data type of varchar. To
avoid confusion it is best to use explicit conversion such as using the
cast\convert functions or to use data types that are the same.

The UNION keyword is simply placed between the 2 select statements, for
example:
SELECT * FROM [first_db].[dbo].[spending_initial]

UNION

SELECT * FROM [first_db].[dbo].[spending_more]

The result of this statement is:

Notice that the following row that is in both tables is not duplicated in the
dataset that is returned to the user:

created_datecategoryamount user_id

2020-07-15COFFEE2.252

Next, change the UNION keyword to UNION ALL and execute the query:
SELECT *

FROM [first_db].[dbo].[spending_initial]

UNION ALL

SELECT *

FROM [first_db].[dbo].[spending_more]

This time you will see that the row that is in both tables is duplicated:

To make the duplicates easier to spot you can add the ORDER BY clause to
the end of the statement as shown:

SELECT * FROM [first_db].[dbo].[spending_initial]

UNION ALL

SELECT * FROM [first_db].[dbo].[spending_more]

ORDER BY created_date

To get the following result :


EXCEPT

The EXCEPT keyword is placed between the 2 select statements just like the
UNION keyword.

The EXCEPT keyword will return all the rows from the first SELECT
statement that do not exist in the second SELECT statement.

For example:
SELECT * FROM [first_db].[dbo].[spending_initial]

EXCEPT

SELECT * FROM [first_db].[dbo].[spending_more]

3 rows are returned as the result for this statement, the one row that is
omitted from the spending_initial table is the one that is duplicated in the
spending_more table.

INTERSECT

The INTERSECT keyword returns rows that are the same in both the first
and second SELECT statements. This can be useful to check for duplicate rows
between tables.

For example the following queries with the INTERSECT keyword between
will return the 1 row that exists in both tables:
SELECT * FROM [dbo].[spending_initial]

INTERSECT

SELECT * FROM [dbo].[spending_more]

The result of this statement is:


Quiz

Section 3. Advanced Queries

Section Topics include - Aggregation and String functions, Conditional


statements and joining data in tables.

Question 1

Why will this statement cause an error ?

SELECT SUM(amount) as total , user_id from spending_initial

GROUP BY category

Question 2

How would to remove whitespace from the left and right side of a string?

Question 3

Which Conditional statement can be used in a SELECT statement ?


Section 4. Sql Beyond the Basics
Now that the basics of sql development have been covered Section 4 carries
on by introducing more development techniques such as using Stored
Procedures, Functions and Views, Triggers and database design rules.

1. Database Constraints
Next we will cover database constraints.

Database constraints allow you to make extra checks on the data in your
tables before the data is saved.

You have already encountered one form of database constraint when creating
the tables that checks if a NULL value is allowed in the field or not. This
database constraint is used to force applications to enter some value even if it is
a default value in fields that do not allow NULL values.

Using data types correctly provides another type of check constraints. For
example if the data type was set to numeric(5,2) the larger number you could
enter would be 999.99 (5 digits in total with 2 after the decimal point).

Next we will cover the following types of database constraints :

1. Check constraints
1. Adding using SSMS
2. Adding when you create a table

2. Foreign key constraint


CHECK Constraints
A simple check constraint allows you to create rules for the values that are
allowed to be entered into the fields of your table.

The expressions used to define the check constraint can use tsql keywords
such as 'LIKE'. In the next example we will add a check constraint to the
spending_users table to check that all budgets are less than 1000.

Adding a CHECK CONSTRAINT using SSMS

1. Expand the Databases folder - first_db database - Tables -


dbo.spending_users. Here you will see a folder called 'Constraints' as
shown:

2.
3. Right click on the Constraints folder and select the 'New Constraint'
option...
4. Click on the Expression field and enter the following expression:

budget<1000
5. This expression simply checks that the value of the budget field is less
than 1000.
6. Optionally you can add a description such as 'Check Budget Limit is
less than 1000'.
7. Click the Close button to close the CHECK CONSTRAINT dialog box
and then press Ctrl+S to save the table.
8. Right click on the Constraints folder and select the Refresh button,
now when you expand the Constraints folder the constraint you created
called CK_spending_users should now be displayed.
9. The default name for the check constraint is 'CK_spending_users'.
10. To test the check constraint you will need to make a couple of
changes. First select the Tools -> Options menu option, then select the
Designers - Table and Database Designers option on the left side
menu.

11. Remove the tick from the 'Prevent Saving changes that require table
re-creation' option and click the OK button.
12. Right click on the 'spending_users' table and click on the Design
option. Change the data type for the budget field to be numeric(6,2).
You need to make this change if you want to be able to enter a number
in the budget field that is greater than 999.99.
13. Press Ctrl+S to save the table and select 'Yes' to any warnings.
14. To test the check constraint simply edit the table by right clicking on
the table name and selecting 'Edit Top 200 rows'. Try to change the
budget field to be 1000 or greater. You should get an error message
similar to the one below letting you know that the check constraint has
prevented entering a number that is too large.

15. You can get a list of check constraints in a database by querying the
table sys.check_constriants.

select * from sys.check_constraints


16. To find the table name you need to use the OBJECT_NAME function
on the parent_object_id field, for example:

select OBJECT_NAME(parent_object_id) as table_name ,*


from sys.check_constraints

The following table should be displayed:

Next we will continue with Primary Key Constraints.


Key Constraints

Primary Key
The purpose of a primary key is to uniquely identify each row in the table.

You can set the primary key of a table before\after you create the table as
long as the data you wish to use as the primary key only contains unique values
and no NULL values.

Set the Primary Key using SSMS

1. Expand the first_db database,then the Tables folder.

2. Right click on the spending_users table and select Design.


3. Right click on the user_id field and select 'Set Primary Key'. A key
symbol will appear to the left of the field name.
4. Press Ctrl+S to save the changes to the table.
5. If you have 2 rows in the spending_users table that have the same
user_id you will get the following error when you try to set the user_id
field as a primary key and save the changes.

6. Once you have saved the table without any errors, close the design
window.
7. Right click on the spending_users table and select 'Edit Top 200
Rows'.
8. Try to add a user_id that already exists in the table and you should get
the following error:
9. Open a new query window and run the following command the list the
key constraints in the table:

select * from sys.key_constraints

10. The primary key constraint you have just created is returned.
FOREIGN KEY CONSTRAINTS

A foreign key (FK) is a field in one table that refers to the primary key (PK)
in another table, this creates a link between the 2 tables.

Therefore the primary key must exist before it can be used in the foreign key.

1. In the example we will create a foreign key in the spending_initial


table using the user_id field and a primary key in the spending_users
table using the user_id field.

2. If you have followed the example in the previous section on


PRIMARY KEYS you should already have set the user_id field in the
spending_users table to be a primary key.
3. Next we will setup a foreign key in the spending_initial table and test
the constraint.

Setup a foreign key

1. To setup the user_id field in the spending_initial as a foreign key first


you will need to remove any rows from the spending_initial table
when the user_id does not exist in the spending_users table.

2. Right click on spending_initial table and select the Design option.


3. Right click on the user_id field and select the 'Relationships...' option.
4. Click on the Add button in the 'Selected Relationship' box.
5. Expand the 'Tables And Columns Specification' option and click on the
'...' button.

6. The 'Tables and Columns' dialog box will be displayed where you can
set the primary key table as 'spending_users' and the foreign key table
as 'spending_initial. Both tables will be using the field 'user_id' as
shown:

7. The default name of the foreign key constraint is :


FK_spending_initial_spending_users
8. Click on the OK button
9. Expand the 'INSERT And UPDATE Specification' option.
Notice that the settings for the 'Delete Rule' and 'Update Rule' options
are set to 'No Action'.
10. Click on the Close button.
11. Press Ctrl+S to save the table changes.
12. You will get the following warning:

13. Click on the Yes button to continue.


14. If there are rows where the user_id exists in the spending_initial table
but not in the spending _users table you will get the following error
when you try to save the table:

'spending_users' table saved successfully

'spending_initial' table

- Unable to create relationship 'FK_spending_initial_spending_users'.

The ALTER TABLE statement conflicted with the FOREIGN KEY


constraint "FK_spending_initial_spending_users". The conflict occurred in
database "first_db", table "dbo.spending_users", column 'user_id'.

15. If you expand the spending_inital table, Keys folder you will now see
the foreign key you have just created:
16.
17. You can also see the list of foreign keys by running the following
query:
select * from sys.foreign_keys

Adding Rows To Table Using A Foreign Key

1. Right click on the spending_initial table and select 'Edit Top 200
Rows'.

2. Enter a new row\update a row and use a user_id that does not exist and
you should get the following error:

3.
4. Add a row for a user_id that does exist.

Changing Primary Key In Foreign Key Relationship

Delete Rule
The Delete Rule will delete all the rows in the table that has the foreign key
when the associated row is deleted from the table with the primary key. In
this example if you deleted the row from the spending_users table all the
rows with that user_id in the spending_initial table would also be deleted.

1. Expand the spending_initial table, then the Keys folder.

2. Right click on the Foreign key and select Modify.


3. The 'Foreign Key Relationships' box will be displayed.
4. Expand the 'INSERT And UPDATE Specification' option.
Notice that the settings for the 'Delete Rule' and 'Update Rule' options
are set to 'No Action'.
5. Select the 'Delete Rule' option and choose 'Cascade' from the
dropdownlist.
<delete-cascade>
6. Click on the Close button.
7. Press Ctrl+S to save the table and 'Yes' to continue.
Test The Cascade Delete

In this example we are going to delete the user_id 1 from the spending_users
table and because with have the 'Cascade' option setup on the foreign key
relationship all the rows with a user_id of 1 in the spending_initial table should
also be deleted.

1. For this example to work first check that you have rows with a user_id
of 1 in both the spending_initial and spending_users tables.

2. Select the spending_users table, right click and select 'Edit Top 200
Rows'.
3. Highlight the row with user_id 1
4. Press the delete key and press the Yes button when you get the
following warning:

5. Check the rows that now exist in the spending_initial table:


SELECT [created_date],[category],[amount],[user_id]

FROM [first_db].[dbo].[spending_initial]

6. You should see that the rows with a user_id of 1 no longer exist in the
spending_initial table.
Updating Foreign Key Values

1. Expand the spending_initial table, then the Keys folder.

2. Right click on the Foreign key and select Modify.


3. The 'Foreign Key Relationships' box will be displayed.
4. Expand the 'INSERT And UPDATE Specification' option.
5. Set the 'Update Rule' option to Cascade.
6. Close on the Close button.
7. Press Ctrl+S to save the table and 'Yes' to continue.
8. To test the 'Cascade' option of the Update we will change the user_id
of 3 to 13 in the spending_users table.
9. Making this change will update any rows with a user_id of 3 in the
spending_initial table from 3 to 13 as well.
10. Select the spending_users table, right click and select 'Edit Top 200
Rows'.
11. Change the user_id if 3 to 13.
12. Run a SELECT query against the spending_initial table.

SELECT [created_date],[category],[amount],[user_id]

FROM [first_db].[dbo].[spending_initial]

13. You will see that the user_id that was previously 3 is now set to 13.
Other settings for the Delete\Update action

14. In the example for the Update\Delete action in both examples we


chose the Cascade option.
The reason for this is that it is the most useful option to keep the data
in sync between the primary key and foreign key.
15. Other options exist that set the values in the foreign key
table(spending_initial) to NULL or the default option when the
Primary key does not exist.
2. Templates
Templates provide a structure for creating sql development objects such as
stored procedures, view and functions.

Using templates can:

1. Speed up development by saving time on typing out the same tsql


statements.

2. Standardized your development by providing a pre-defined structure


for creating various objects within the sql database.
3. Remind you to fill in various details such as Author name, create date
and descriptions which might be overlooked.
4. To view some of the many templates that are available to the user
select the View->Template Explorer option.

5.
6. Try not to let it confuse you that when you select the 'Template
Explorer' option a view that has 'Template Browser' is displayed, it
should say 'Template Explorer'. Expand the Stored Procedure folder.

7. Double click on the 'Create Procedure Basic Template' option to open


the template in a new query window.
8. From the Query menu you select the 'Specify Values For Template
Parameters' option as shown that will display all the parameters that
can be completed for the template.

9. The location of the templates on your computer is the following folder,


if you intend to made changes to the templates it is worth making a
backup of this folder first:

C:\Users\<USERNAME>\AppData\Roaming\Microsoft\SQL
Server Management Studio\14.0\Templates\Sql

Create a New Template

1. Within the Template Explorer, right click on the 'SQL Server Template'
icon and select New->Folder:

2.
3. Rename the folder 'my templates'.
4. Right click on the folder and select New->Template

The new template is created in:

C:\Users\<USERNAME>\AppData\Roaming\Microsoft\SQL
Server Management Studio\14.0\Templates\Sql\my templates
5. Rename the new template 'my_first_template'.
6. Double click on the new template and a query window will be opened.
7. Within the new query window add the following statement:
SELECT * from [dbo].[spending_initial]
8. The format for adding parameters to a template is:

<parameter_name, data_type, value>


9. To change this template to add the following parameter in a WHERE
clause:

<category,varchar(20),COFFEE>
10. So the query should now be, we have set the default value for this
parameter to 'COFFEE':

SELECT category from [dbo].[spending_initial]

WHERE category= <category,varchar(20),COFFEE>

11. To edit this template simply right click on the template name and
select edit.
12. To access the Template parameters quickly select Alt+Q, then S.

13. This used to be Ctrl+Shift+M and the comments in the standard


templates still say to use these keys to display the parameters but they
no longer work.
Code Snippets

Along with templates code snippets work well to really boost your
productivity when developing in sql.

It is best to start using code snippets\templates when you start learning


sql as they will save you alot of time and frustration trying to remember the
layout of various sql functions or frequently used blocks of code.

1. Open a 'New Query' window.


2. To use the code snippets already available press Ctrl+K, then Ctrl+X.

3. Select the stored procedure folder.

4. Select 'Create Procedure Basic Template'.The following code will be


added to
the query window:
5. CREATE PROCEDURE dbo.Sample_Procedure
@param1 int = 0,
@param2 int
AS
SELECT @param1,@param2
RETURN 0

6. The snippets are stored in the following folder:

C:\Program Files (x86)\Microsoft SQL


Server\140\Tools\Binn\ManagementStudio\SQL\Snippets\1033

7. To add your own snippet you can add a .snippet file to the following
folder:
8. C:\Users\<your own username>\Documents\SQL Server
Management Studio\Code Snippets\SQL\My Code Snippets.
9. Within the SSMS go to the Tools->Code Snippets Manager. Then
click Add and select your My Code Snippets folder.
10. The snippet will then be available within the My Code Snippets
folder.
11. Next is an example code snippet file called my test
snip.snippet2.snippet. To use this just change the information in the
Title, Description, Author and Code tags:

<?xml version="1.0" encoding="utf-8" ?>

<CodeSnippets
xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">

<_locDefinition xmlns="urn:locstudio">

<_locDefault _loc="locNone" />

<_locTag _loc="locData">Title</_locTag>

<_locTag _loc="locData">Description</_locTag>

<_locTag _loc="locData">Author</_locTag>

<_locTag _loc="locData">ToolTip</_locTag>
</_locDefinition>

<CodeSnippet Format="1.0.0">

<Header>

<Title>My Test Snippet title</Title>

<Shortcut></Shortcut>

<Description>My Test snippet</Description>

<Author>Mark ODonovan</Author>

<SnippetTypes>

<SnippetType>Expansion</SnippetType>

</SnippetTypes>

</Header>

<Snippet>

<Code Language="SQL">

My Test tsql code

</Code>

</Snippet>

</CodeSnippet>

</CodeSnippets>
3. Stored Procedures

You have probably used a stored procedure without knowing it as there are
many stored procedures such as sp_who2 which lists current users\processes and
sessions running on the system, you can run the command as:

exec sp_who2

or

sp_who2

The system stored procedures start with 'sp' for example sp_server_info.

When I am creating stored procedures I tend to prefix the name with 'usp'
(for user stored procedure), this is just a naming convention and not a
requirement.

One of the main advantages of using stored procedures is that other


developers \ administrators can run the commands without having to know the
details of the underlying tables in the database.

Create your first Stored Procedure

1. Go to the first_db database.

2. Expand the database folder, then the Programmability folder.


3. Right click on the 'Stored Procedures' folder and select 'Stored
Procedure…' as shown:
4. The following code is generated in a new query window:
-- ================================================

-- Template generated from Template Explorer using:

-- Create Procedure (New Menu).SQL

--

-- Use the Specify Values for Template Parameters

-- command (Ctrl-Shift-M) to fill in the parameter

-- values below.

--

-- This block of comments will not be included in

-- the definition of the procedure.

-- ================================================

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

-- =============================================

-- Author:<Author,,Name>

-- Create date: <Create Date,,>

-- Description:<Description,,>
-- =============================================

CREATE PROCEDURE <Procedure_Name, sysname,


ProcedureName>

-- Add the parameters for the stored procedure here

<@Param1, sysname, @p1> <Datatype_For_Param1, , int> =


<Default_Value_For_Param1, , 0>,

<@Param2, sysname, @p2> <Datatype_For_Param2, , int> =


<Default_Value_For_Param2, , 0>

AS

BEGIN

-- SET NOCOUNT ON added to prevent extra result sets from

-- interfering with SELECT statements.

SET NOCOUNT ON;

-- Insert statements for procedure here

SELECT <@Param1, sysname, @p1>, <@Param2, sysname, @p2>

END

GO

5. You can delete some of the comments and add a name for you stored
procedure of 'usp_myfirstsp'.
6. Next we will enter the select statement that will be returned when we
run the stored procedure. The select statement we are going to use is as
follows:
SELECT *
FROM [first_db].[dbo].[spending_initial]

UNION

SELECT *

FROM [first_db].[dbo].[spending_more]
7. The press Ctrl+S to save the stored procedure, which should look like
the following code:

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

-- =============================================

-- Author: Mark O'Donovan

-- Create date: 31/12/2012

-- Description: My first stored procedure

-- =============================================

CREATE PROCEDURE usp_myfirstsp

AS

BEGIN

-- SET NOCOUNT ON added to prevent extra result sets from

-- interfering with SELECT statements.

SET NOCOUNT ON;

SELECT * FROM [first_db].[dbo].[spending_initial]

UNION

SELECT * FROM [first_db].[dbo].[spending_more]

END

GO
8. Press the Execute button in the toolbar or Alt+X to execute the
statement.
This will not run the stored procedure but instead it creates the stored
procedure object in the database.

The result should be :

Command(s) completed successfully.

9. If you expand the 'Stored Procedures' folder you should now see the
stored procedure you have just created.

Run the Stored Procedure

1. Right click on the stored procedure and select 'Execute Stored


Procedure...'.

2. As there are no parameters for this stored procedure you can just click
the ok button.
3. A new query window will open with the following statement and the
statement will be executed:

USE [first_db]

GO

DECLARE@return_value int

EXEC@return_value = [dbo].[usp_myfirstsp]
SELECT'Return Value' = @return_value

GO

4. The result of this query for my data was :


Changing your Stored Procedure

1. To change the stored procedure, right click on the stored procedure and
select 'Modify'.

2. A new query window will be opened with the following query:

USE [first_db]

GO

/****** Object: StoredProcedure [dbo].[usp_myfirstsp] Script Date: 22/01/2013 21:23:02


******/

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

-- =============================================

-- Author:Mark O'Donovan

-- Create date: 31/12/2012

-- Description:My first stored procedure

-- =============================================

ALTER PROCEDURE [dbo].[usp_myfirstsp]

AS

BEGIN

-- SET NOCOUNT ON added to prevent extra result sets from


-- interfering with SELECT statements.

SET NOCOUNT ON;

SELECT * FROM [first_db].[dbo].[spending_initial]

UNION

SELECT * FROM [first_db].[dbo].[spending_more]

END

3. Notice that the statement for the stored procedure started with
'CREATE PROCEDURE' when you were adding the procedure for the
first time has now changed to 'ALTER PROCEDURE'.
4. We altered and stored procedure to change the SELECT statement to
only return rows when the amount was greater than 10.

SELECT * FROM [first_db].[dbo].[spending_initial]

WHERE amount>10

UNION

SELECT * FROM [first_db].[dbo].[spending_more]

WHERE amount>10

5. Execute the stored procedure by clicking the Execute button or Alt+X.


6. Now run the stored procedure again and the result should change to:

7. Modify the stored procedure again to remove the WHERE clause and
execute the statement to update the object in the database.
Stored Procedure Parameters

Adding parameters to stored procedures can save development time by


making the procedure more flexible so that it can be reused in more situations.

Stored procedure parameters are added after the 'ALTER\CREATE


PROCEDURE <procedure name> ' part of the statement, for example:

ALTER PROCEDURE [dbo].[usp_myfirstsp]

@filter_category varchar(20)

...<rest of the stored procedure>...

8. If you required more than one stored procedure these would be


separated by a comma.
9. All parameters must start with a @ symbol.

The format of the parameter is:

@<parameter name> <data type>

10. Next add the parameter @filter_category to our example stored procedure
as shown in the above example.
11. Add the following WHERE clause to each SELECT statement in the
stored procedure to use the parameter :

WHERE category=@filter_category

12. You stored procedure should now be the same as the following
statement(the comments have been removed to save space):
ALTER PROCEDURE [dbo].[usp_myfirstsp]

@filter_category varchar(20)

AS

BEGIN

SET NOCOUNT ON;

SELECT * FROM [first_db].[dbo].[spending_initial]

WHERE category=@filter_category

UNION

SELECT * FROM [first_db].[dbo].[spending_more]

WHERE category=@filter_category

END

13. Press Alt+X to make the changes to the stored procedure.


14. To Add a default value add the

@filter_category varchar(20) = 'COFFEE'

15. Know when you right click on the stored procedure and select 'Execute
Stored Procedure…' you will see that there is a parameter in the list:

16. Click OK to run the stored procedure without entering any value and
the default value of the parameter will be used which will return only
the rows that have a category of 'COFFEE'.
USE [first_db]

GO

DECLARE@return_value int

EXEC@return_value = [dbo].[usp_myfirstsp]

SELECT'Return Value' = @return_value

GO

17. You can see that the command that is run does not pass any parameter
to the stored procedure. The commands generate by 'Execute Stored
Procedure' option include a '@return_value' variable that indicates if
the procedure ran successfully (if zero is returned) or not.
18. Open a new query window by clicking the new query button.
19. Run the stored procedure as:

exec [dbo].[usp_myfirstsp]
20. You can add parameters to the end of the stored procedure name using
the format @param=value, for example:

exec [dbo].[usp_myfirstsp] @filter_category='FOOD'

21. This command will return just the rows with a category of 'FOOD', as
shown:

22.
23. When you pass a parameter to the stored procedure using the ‘Execute
Stored Procedure' option , for example:

24.
25. The following text is generated:
USE [first_db]

GO

DECLARE@return_value int

EXEC@return_value = [dbo].[usp_myfirstsp]

@filter_category = N'CAR'

SELECT'Return Value' = @return_value

GO

4. Views
Views are simply SELECT statements.

Views allow you to reduce complex select statements into a simple select
query.

Views are similar to inline table valued functions but you cannot pass
parameters to VIews.

View Requirements

1. All tables must be in the same database.


2. Any user-defined functions referenced in the view must have been
created with the SCHEMABINDING option as well.
3. The AVG, MAX, MIN aggregate functions aren’t allowed in the
SELECT statement.
4. You can’t use UNION, TOP, ORDER BY, DISTINCT, COUNT(*)
5. If you would aggregate functions in a view you can use it to update
data.
6. user-defined functions must be created with SCHEMABINDING
option.

Create a view
1. Expand the first_db database, Views folder.

2. Right click on the view folder and select the 'New View...' option

3. The 'Add Table' dialog will appear to assist with the creation of your
view.
4. There are 4 tabs in the 'Add table' dialog which are:

Tables
Views
Functions
Synonyms
5. Click the Close button on the 'Add Table' dialog and we are going to
create the SELECT statement using tsql.
6. In this example we will add a SELECT statement to combine the rows
from the spending_initial and spending_more tables.

SELECT [created_date] ,[category] ,[amount] ,[user_id]

FROM [first_db].[dbo].[spending_initial]

UNION

SELECT [created_date] ,[category] ,[amount] ,[user_id]


FROM [first_db].[dbo].[spending_more]

7. Press Ctrl+S to save the view, set the name of the view to
'spending_all' and press the OK button.
8. The following warning will appear, just click the ignore button.

9. Close the query window, right click on the Views folder and select
Refresh to see the newly created view.

Test the view

1. Now you can test the view by running the following select statement:
use first_db

select * from [dbo].[spending_all]

2. All the rows from the spending_initial and spending_more tables will
be returned to the user.
Updating a view

1. Right click on the spending_all view and select Design.

2. Click the OK button on warning dialog box.


3. Change the select statement to:

SELECT created_date, category, amount, user_id

FROM dbo.spending_initial

4. Press Ctrl+S to save the view.


5. Now you can run the following update statement that will update the
table used in the view

update [dbo].[spending_all]

set category='TEA'

where category='COFFEE'

6. There are some restrictions on when you can use a view to update
underlying tables such as you cannot use the view with an update if
aggregate functions are used in the view.
7. You cannot update a view if the select uses any of the following
keywords UNION, UNION ALL, CROSSJOIN, EXCEPT, and
INTERSECT.
8. The columns to be modified are not changed by GROUP BY,
HAVING, or DISTINCT.

Schemabinding
SCHEMABINDING option prevents any changes being made to the design
of the tables used in the view.

1. The tsql to create our view is :

CREATE VIEW [dbo].[spending_all]

AS

SELECT created_date, category, amount, user_id

FROM dbo.spending_initial

2. You can create the view with the SCHEMABINDING option using the
following tsql:

CREATE VIEW [dbo].[spending_all_bound] WITH SCHEMABINDING

AS

SELECT created_date, category, amount, user_id

FROM dbo.spending_initial

3. Run the following command to drop (delete) the spending_initial


table:
DROP TABLE [spending_initial]
4. You will get the following error:

Msg 3729, Level 16, State 1, Line 7


Cannot DROP TABLE 'spending_initial' because it is being referenced
by object 'spending_all_bound'.
5. Right click on the view spending_all_bound and select Delete.
6. Click the OK button from the 'Delete Object' dialog box.
7. Run the following command to make a backup of the spending_initial
table:

select * into spending_initial_bak


from spending_initial
8. Now run the DROP statement again and this time it will work without
an error:

DROP TABLE [spending_initial]


9. Right click on the spending_initial_bak table and select Rename to
change the table to spending_initial.

List Views

10. You can list the views in your database using the following statement:

select * from sys.views


5. Functions
We will cover 2 different types of functions:

Scalar Functions

Scalar functions return 1 value and can be used anywhere a value is required.

Table-valued functions

Table valued functions return a table of data and can be used as an alternative
to views.

Views can only use 1 select statement whereas tabled-valued functions can
perform more complex queries if required.

There are 2 types of table-valued functions:

Inline

Inline table-valued functions are like views that can accept parameters.

Multi-statement

Multi-statement table-valued functions are more like stored procedures.


Scalar Functions
Scalar functions return 1 value back to the query.

You have already used various functions such as GETDATE() that returns
the current datetime to the query, for example:

SELECT GETDATE()

Example

1. Next we will show you how to create and update a scalar function.

2. In this example we are going to use the spending example to return the
total sum of the budget field in the spending_users table.
3. The query that we will use in the function is:

SELECT SUM(budget) from [dbo].[spending_users]

4. Expand the first_db database, then the Programmability folder, then


the Functions folder.

5. Right click on the 'Scalar-valued Functions' option and select the 'New
Scalar-valued Function...' option:

6. The template for the scalar-valued function will be displayed in a new


query window.
7. Press Alt+Q,S to display the dialog box to specify the template
parameters.

8.
9. Enter the values as in the following screenshot and click the OK
button:

10.
11. Delete the comments at the top of the template and press Ctrl+S to
save the script.
12. Your script should look like the following code:
SET ANSI_NULLS ON

GO
SET QUOTED_IDENTIFIER ON

GO

-- =============================================

-- Author:Your Name

-- Create date: Current Date

-- Description:Return the budget total

-- =============================================

CREATE FUNCTION fn_budget_total

-- Add the parameters for the function here

RETURNS

AS

BEGIN

-- Declare the return variable here

DECLARE

-- Add the T-SQL statements to compute the return value here

SELECT =

-- Return the result of the function

RETURN
END

GO

13. Now you can fill out the RETURNS,DECLARE, SELECT and
RETURN parts of the function.

Returns

14. The RETURNS part of the function specifies by data type that will be
returned to the query. In this example we will return a numeric value
so set RETURNS to:

RETURNS numeric(5,2)

Declare
15. This is to specify the variable that will be returned to the user, this
should match the data type in the RETURNS statement.

DECLARE @budgettotal numeric(5,2)

Select

16. The SELECT statement will be used to set the value you have just
defined (@budgettotal). Set the variable using the format <variable>=
<field> in the field list of the SELECT statement.
17. If you are not using an aggregation function such as SUM() and there
is the possibility that multiple rows are returned from the query you
will need to add TOP 1 so that only 1 row is ever going to be returned,
for example:

SELECT TOP 1 username from users

WHERE user='Mark'

Return
18. This is the statement to return the variable to the user, in this example
we simply specify the variable that we declared and set using the select
statement:

RETURN @budgettotal

19. As an alternative we could have just returned the value of the SELECT
statement, for example.

RETURN (SELECT SUM(budget) from [dbo].[spending_users])

20. In this example you will get an error message if you do not place the
SELECT statement within brackets.

Changing the function

21. In the same way as the stored procedures when you need to modify
functions you need to change the statement from a 'CREATE
FUNCTION' to an 'ALTER FUNCTION'.

Running the function

22. To execute this function within a select statement, open a new query
window.
23. Type the following statement:
select dbo.fn_budget_total()
24. Press Alt+X to the execute statement and you should get the total
returned.
25. One difference between the function and the stored procedure is that
you can execute the function when select data from other tables as well
, for example :
select dbo.fn_budget_total() as budget_total,*
from [dbo].[spending_users]

Function Parameters

1. In this same way as we added a parameter to the stored procedure we


can add a parameter to the function.

2. In this example we add a parameter to filter the result by the


department of the user.
3. The script to update this function should be:

ALTER FUNCTION fn_budget_total

@dept varchar(50)

RETURNS numeric(5,2)

AS

BEGIN

DECLARE @budgettotal numeric(5,2)

SELECT @budgettotal=SUM(budget) from [dbo].[spending_users]

where department=@dept
RETURN @budgettotal

END

GO

4. As we do not have a default value for this function if you try to run the
following SELECT statement:
5. You will get the following error:

Msg 313, Level 16, State 2, Line 1

An insufficient number of arguments were supplied for the procedure or function


dbo.fn_budget_total.

6. To add a default for the parameter (just like a stored procedure) change
the parameter as follows:
@dept varchar(50) = 'SALES'
7. Unlike a stored procedure you cannot run the function without a value
even if there is a default value. You need to enter the keyword
DEFAULT as shown:
select dbo.fn_budget_total(DEFAULT)
8. You can run the function with another value just by entering the value
within single quotes. The next example will return the budget total for
all users within the IT department.

select dbo.fn_budget_total('IT') as budget_total


9. If you have more than one parameter you must list them with the
brackets of the function in the same order as they are defined.
10. The power of functions comes from combining them with results
returned from other SELECT statements.
11. For example the query below returns the departments from the
spending_users table but also passes the value of each unique
department to the function fn_budget_total so the budget total for
those departments is also returned.
select distinct department

,dbo.fn_budget_total(department) as budget_total

from [dbo].[spending_users]

12. The result of this query will be:


Table-valued functions
Where scalar-valued functions return 1 value, table-valued functions will
return a table of data.

We will now cover inline and multi-statement table-valued functions.

Inline

Inline table-valued functions are like views that can accept parameters.

To demonstrate how to use table-value functions we will create a function


that will return all the users from the spending_users table when the department
field is the same as the parameter passed to the function.

1. Within the first_db database you have created expand the


Programmability folder, then Functions.

2. Right click on the Table-valued Functions folder and select 'New


Inline Table-valued Function...'.

3.
4. The template for the inline table-valued function will be displayed in a
new query window.
5. Select the menu option Query->Specify Values for Template
Parameters.. or press Alt+Q,S.

6. Enter the template parameters as shown and click the OK button:


7. Remove the comments from the top of the script and the comma after
the single parameter.
8. Your script should now look like the following text:
SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

-- =============================================

-- Author:Your Name

-- Create date: Created Date

-- Description:Rows for department

-- =============================================

CREATE FUNCTION fn_dept_users

(
-- Add the parameters for the function here

@dept varchar(50)

RETURNS TABLE

AS

RETURN

-- Add the SELECT statement with parameter references here

SELECT 0

GO

9. Before continuing save the current script.


10. Now add the following SELECT statement to the script to replace the
'SELECT 0'.

select

[user_id]

,[firstname]

,[lastname]

,[department]

,[budget]

FROM [first_db].[dbo].[spending_users]

WHERE department=@dept
11. Execute the statement and you should get a the following result if all is
correct:
Command(s) completed successfully.
12. The full script should be:

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

-- =============================================

-- Author:Your Name

-- Create date: Created Date

-- Description:Rows for department

-- =============================================

CREATE FUNCTION fn_dept_users

-- Add the parameters for the function here

@dept varchar(50)

RETURNS TABLE

AS

RETURN

select

[user_id]
,[firstname]

,[lastname]

,[department]

,[budget]

FROM [first_db].[dbo].[spending_users]

WHERE department=@dept

GO

13. Execute the following statement to use the function:

SELECT * FROM dbo.fn_dept_users('IT')


14. The result of this statement should be:

15. In the same way as scalar function you need to change the function
from 'CREATE FUNCTION' to 'ALTER FUNCTION' to modify the
function in the database.
Multi-statement Function
Multi-statement table-valued functions are more like stored procedures.

Rather than a single select statement you can create a table using complex
queries and multiple statements.

As you have probably just started sql development you will not probably not
require them just yet but it is good to know they exist.

The example we will cover here will be straight forward one that selects
values from 2 tables and returns them to the user.

1. In this example first we get the fullname from the spending_users


table.
Then we get the spending for this user from the spending_initial table.
The full code for this examples is:

--This will return data about the user and their spending

CREATE FUNCTION fn_getuser_spending

@user_id int

RETURNS

@spending TABLE

username varchar(40) NOT NULL

,category varchar(20) NOT NULL

,amount numeric(5,2) NOT NULL

)
AS

BEGIN

DECLARE @username varchar(40), @category varchar(20), @amount numeric(5,2)

--Get the username

SELECT @username= [firstname] +' '+[lastname] from [dbo].[spending_users]

WHERE user_id=@user_id

SELECT

@category = category

,@amount = amount

FROM [dbo].[spending_initial]

WHERE user_id=@user_id

INSERT @spending

SELECT @username,@category,@amount

RETURN

END

GO

2. In this statement first we have setup a single parameter for the user_id.
3. Then we define the table that will be returned to the user as follows:

RETURNS

@spending TABLE

username varchar(40) NOT NULL


,category varchar(20) NOT NULL

,amount numeric(5,2) NOT NULL

4. Next we define the variables that will be used to store the results of the
SELECT statements.
5. DECLARE @username varchar(40), @category varchar(20),
@amount numeric(5,2)
6. The first SELECT statement queries the spending_users table,
concatenates the firstname and lastname field and stores it in the
@username variable.

SELECT @username= [firstname] +' '+[lastname] from [dbo].


[spending_users]

WHERE user_id=@user_id

7. The second SELECT statment reads the category and amount fields
from the spending_initial table and stores the result in the @category
and @amount variables.

SELECT @category = category

,@amount = amount

FROM [dbo].[spending_initial]

WHERE user_id=@user_id

8. Finally the results stored in the variables are inserted into the
@spending table to be returned to the user.
INSERT @spending

SELECT @username,@category,@amount

9. We can execute this function just like the inline table-valued function
using the following statement:

select * from fn_getuser_spending('2')


10. This query returns the following result:

11.
12. In the same way as scalar function you need to change the function
from 'CREATE FUNCTION' to 'ALTER FUNCTION' to modify the
function in the database.
6. Synonyms

Synonyms are useful for creating aliases for tables. So you can easily
change the table\database that your tsql code is referring without changing your
tsql code. For example you might want to change the database your code is
referring to when moving your tsql from testing to a live environment when
working within a company.

The format is:

CREATE SYNONYM <table alias> FOR <target table>

For example:

CREATE SYNONYM dbo.userlist FOR first_db.[dbo].[spending_users]

Now you will be able to run the following select command that will return
the rows from the spending_users table.
select * from userlist

NOTE: that the alias from the synonym does not exist in the Tables folder
but the Synonyms folder as shown:

You can list all the synonyms used in your database using the following
statement:
select * from sys.all_objects where type='SN'

or

select * from sys.synonyms


The field base_object_name in this statement gives the target table.
7. Triggers
Triggers allow you to automatically run a type of stored procedure when the
data is altered in a table (UPDATED,INSERTED or DELETED) or an action is
taken on a database such as creating a table.

One practical use of triggers is to create an audit of what is happening to a


table.

In the next examples to demonstrate triggers we will create an audit table.

Setup the Audit Table

1. Click the 'New Query' button to open a new query window and add the
following statement

use first_db

CREATE TABLE [dbo].[spending_audit](

[id] [int] IDENTITY(1,1) NOT NULL,

[audit_category] [varchar](100) NULL,

[message] [varchar](max) NULL,

[created_dttm] [datetime] NULL,

2. In this statement the first line 'use first_db' just changes the context of
the SSMS to the first_db database so that any commands executed are
applied to the first_db database.
3. Next is the CREATE TABLE statement that creates the audit table.
The the fields should be familiar to you except the [id] field which is
using the IDENTITY function:
[id] [int] IDENTITY(1,1) NOT NULL
4. The IDENTITY function allows you to create an integer field that
automatically increments when each row is added to the table.
5. The first parameter is the starting number and the second parameter
specifies how much to increment the field by every time a row is
added. In this example IDENTITY(1,1) means it will start and 1 and
increment by 1 each time.
6. Because the [id] fields uses an IDENTITY function we do not have to
include this field when using the INSERT statement to add data to this
table.

Trigger On a Table
The type of triggers that we are going to cover next are those that manipulate
the data in tables for example Insert, Update and Delete statement which are also
known as DML (Data Manipulation Language) events.

Create a Trigger - INSERT

1. Next we are going to create a trigger on the spending_initial table that


adds a row to the spending_audit table each time a row is inserted into
the spending_initial_table.
2. Expand the spending_initial table.

3. Right click on the Triggers folder and select 'New Trigger...'.

4. The template for the trigger will appear in a new query window.
5. Remove the green comments at the top of the template and press
Alt+Q,S to fill in the template parameters as shown in the screenshot
below:
6. You should now have the following statement in your query window.
SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

-- =============================================

-- Author:Your name

-- Create date: Created Date

-- Description:Add audit log when insert spending

-- =============================================

CREATE TRIGGER dbo.trig_spending_initial_insert

ON dbo.spending_initial

AFTER INSERT

AS

BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from

-- interfering with SELECT statements.

SET NOCOUNT ON;

-- Insert statements for trigger here

END

GO

7. Now you are ready to add the code to insert the audit record into the
spending_audit table.

-- Insert statements for trigger here

INSERT INTO [dbo].[spending_audit]([audit_category],[message],[created_dttm])

VALUES ('SPENDING','row added for category '+ (SELECT inserted.category FROM


INSERTED),GETDATE())

8. The full trigger should be :

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

-- =============================================

-- Author:Your name

-- Create date: Created Date

-- Description:Add audit log when insert spending


-- =============================================

CREATE TRIGGER dbo.trig_spending_initial_insert

ON dbo.spending_initial

AFTER INSERT

AS

BEGIN

-- SET NOCOUNT ON added to prevent extra result sets from

-- interfering with SELECT statements.

SET NOCOUNT ON;

-- Insert statements for trigger here

INSERT INTO [dbo].[spending_audit]([audit_category],[message],[created_dttm])

VALUES ('SPENDING','row added for category '+ (SELECT inserted.category FROM


INSERTED),GETDATE())

END

GO

9. Press Alt+X or the Execute button to create the trigger object in the
database.
10. Expand the triggers folder to check that the trigger now exists.
11. As usual if you need to alter the trigger you will need to change the
'CREATE TRIGGER' to 'ALTER TRIGGER'.

Test Trigger

1. To test the trigger right click on the spending_initial table and select
'Edit Top 200 Rows' to insert a new row into the table.
2. You can then check the spending_audit table to check that a row has
been inserted with the correct message,audit_category and
created_dttm fields.

For example:
Trigger on a Database
Triggers on databases are run when certain DDL events occurs such as
CREATE\ALTER\DROP various database objects such as tables and views.

One practical use of these types of triggers is to prevent users from creating
tables in a database or to log security issues such as someone trying to DROP
(remove) a table or view from the database.

Create a Database Trigger


In this example we are going to create a trigger on the first_db database to
prevent users from creating tables in the database.

The format of the CREATE TRIGGER statement is:

CREATE TRIGGER <trigger name> ON DATABASE

FOR <DDL EVENT such as CREATE_TABLE,DROP_TABLE>


AS

BEGIN

...Statments to execute...

END

1. Create a new query window and enter the following create trigger
statement:
CREATE TRIGGER trig_create_table ON DATABASE

FOR CREATE_TABLE

AS

BEGIN

PRINT 'You are not allowed to create tables'


ROLLBACK;

INSERT INTO [dbo].[spending_audit]([audit_category],[message],[created_dttm])

VALUES ('TABLE','prevented from creating table',GETDATE())

END

2. When this trigger is fired the PRINT statement will display a messages
to the user, the ROLLBACK statement prevents the CREATE TABLE
statement that fired this trigger from being executed.
3. Finally we log a simple message to your spending_audit table so that
we know someone was trying to create a table in our database.
4. Execute the above statement by pressing Alt+X to create the trigger.
You can see the new trigger listed in the Programmability folder, then
Database Triggers ( you will probably have to right click on this folder
and select Refresh for the trigger to appear).

Test Database Trigger

5. Now try to create a trigger by creating a simple table such as :


CREATE TABLE my_trigger_test

(
testfield int NULL
)

6. You should get the following message:


You are not allowed to create tables

(1 row(s) affected)
Msg 3609, Level 16, State 2, Line 1
The transaction ended in the trigger. The batch has been aborted.

7. If you run a SELECT statement on the spending_audit table will find a


row has been added to the table.
8. Other DDL events you might want to create triggers for are
DROP_TABLE and ALTER_TABLE instead CREATE_TABLE.
9. You could add an if statement to the trigger so that it only prevents
tables being created under certain conditions such as certain users or
certain times of the day.

View all triggers in database

1. To view all the triggers in the database run the following statement:

select * from sys.triggers

2. This statement will show you the triggers in your database and the
parent_class_desc will identify the trigger as a database trigger if the
field is set to 'DATABASE' as shown:

Disable\Enable triggers

Sometimes you may wish to disable triggers, for example if you have a
trigger that prevents creating tables and you wish to do some sql development.

The format to disable a trigger is:

DISABLE TRIGGER <trigger name> ON <DATABASE\object such as a


table\ALL SERVER>

1. For example to disable\enable the database triggers we have just


created you would use the following statements:

DISABLE TRIGGER trig_create_table ON DATABASE

ENABLE TRIGGER trig_create_table ON DATABASE

2. Whereas to disable\enable the DML trigger we created in previous


examples you would use the following statements:

DISABLE TRIGGER trig_spending_initial_insert ON spending_initial

ENABLE TRIGGER trig_spending_initial_insert ON spending_initial

3. If you now run the select statement on the sys.triggers table you will
now see that the is_disabled field has been set to 1 if the trigger is
disabled and 0 if it is enabled.
4. When a dml trigger is disabled you will see a red cross on the icon
within the triggers folder of the table:
5. For a DDL event trigger there is no change to the icon when it has
been disabled.
'Instead of' Triggers

1. There are 2 modes that determine when a trigger is run, these are:

AFTER (default mode)

INSTEAD OF

2. The examples of triggers we have covered already are examples of


AFTER triggers for example if you look at the CREATE TRIGGER
statements we used you will see 'AFTER TABLE' for the DML event
trigger.
3. The AFTER trigger will only be run after the statement that fired the
trigger completed without any errors ie: inserting a row into a table.
4. Next we will cover the 'INSTEAD OF' type of trigger.
5. In this example we will add a trigger to the spending_users table that
prevents users being added to the table, instead of inserting the row we
will log the action to the spending_audit table.
6. To perform this example we are going to go back and change the script
we used for the DML trigger example which was :

ALTER TRIGGER dbo.trig_spending_initial_insert

ON dbo.spending_initial
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

-- Insert statements for trigger here


INSERT INTO [dbo].[spending_audit]([audit_category],[message],
[created_dttm])
VALUES ('SPENDING','row added for category '+ (SELECT
inserted.category FROM INSERTED),GETDATE())
END

7. Replace the 'AFTER INSERT' line with:

INSTEAD OF INSERT

8. The full example is:

CREATE TRIGGER dbo.trig_spending_users_insert


ON dbo.spending_users
INSTEAD OF INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

-- Insert statements for trigger here


INSERT INTO [dbo].[spending_audit]([audit_category],[message],[created_dttm])
VALUES ('USERS','prevented from adding user '+ (SELECT inserted.firstname + '
'+inserted.lastname FROM INSERTED),GETDATE())

END

9. Press Alt+X to create this trigger in the database.


10. Right click on the spending_users table and select 'Edit Top 200
Rows'.
11. Enter a new row, there will be no popup error when the row is added
but you should see a red icon with the following message:
12. Now press the execute button to refresh the data and you will see that
the row you have just entered disappears.
13. Right click on the spending_audit table select click 'Select Top 1000
Rows' to check that the trigger has added a row into your audit table.

2 SPECIAL TABLES

Within the triggers we have referred to 2 tables called:

INSERTED

DELETED

These tables contain the values for the row that has been inserted\deleted by
the user.

If the data is being updated there would be one field for the new value of the
field in the inserted table and another field for the old value in the deleted table.
For example:

1. The following trigger will be fired when an UPDATE statement is


applied to the spending_initial table.

ALTER TRIGGER dbo.trig_spending_initial_update

ON dbo.spending_initial

AFTER UPDATE

AS

BEGIN

SET NOCOUNT ON;

DECLARE @new_amount numeric(5,2)

DECLARE @old_amount numeric(5,2)


DECLARE @category varchar(20)

SELECT @old_amount=deleted.amount from DELETED

SELECT @new_amount=inserted.amount,@category=inserted.category from INSERTED

INSERT INTO [dbo].[spending_audit]([audit_category],[message],[created_dttm])

VALUES ('AMOUNT UPDATE','updated category '+@category+ ' amount from


'+cast(@old_amount as varchar(10))+' to '+

cast(@new_amount as varchar(10)) ,GETDATE())

END

2. In the statements of this trigger first we declare the variables that will
stored the old\new values of the amount field and the category field.

DECLARE @new_amount numeric(5,2)

DECLARE @old_amount numeric(5,2)

3. DECLARE @category varchar(20)

Then 2 select statements are run the query the DELETED\INSERTED


tables to same the values we require into the variables.

SELECT @old_amount=deleted.amount from DELETED

SELECT @new_amount=inserted.amount,@category=inserted.category
from INSERTED

Finally we run an INSERT statement to add a row to our audit table


called spending_audit:
INSERT INTO [dbo].[spending_audit]([audit_category],[message],[created_dttm])
VALUES ('AMOUNT UPDATE','updated category '+@category+ ' amount from
'+cast(@old_amount as varchar(10))+' to '+
cast(@new_amount as varchar(10)) ,GETDATE())

4. Note that in the INSERT statement we need to convert the data type of
the @old_amount and @new_amount variables from numeric data
types to varchar data types so that they can be concatenated into the
string used for the message field. If we did not use the CAST function
to change the data type of these variables we would get an error when
the trigger was fired.
5. To test this trigger right click on the spending_initial table and select
'Edit Top 200 Rows' then change the amount in one of the rows and
press the tab key until the cursor goes to the next row to save the data.
6. Next right click on the spending_audit table and click on the 'Select
Top 1000 Rows' option, you should see a message such as :

updated category COFFEE amount from 2.25 to 5.00

7. This shows that the old and new values of the amount field have been
obtained from the DELETED and INSERTED tables within the
trigger.

8. Database Design
Next we are going to cover the basics of database design.

The aim hear (as ever) is not to bore you rule after rule about how the perfect
database would be designed so that you read it once and instantly forget it, but
instead focus on the core rules that will make the most difference to your
development.

The design rules we will cover will become more important when you are
dealing with large tables of data or other sql developers who are using the same
rules.
The rules that we are going to cover next are called 'Normal Forms' and
when you apply this rules to your database design you say you have 'Normalized'
the database or refer to the process as 'Normalization'.

We will cover the first 3 normal forms here which are the most important to
remember and apply on a regular basis. The are 5 normal forms but for most
purposes the first 3 normal forms are more than enough to reduce the
redundancy in the database.

As usual we will demonstrate the ideas here using our spending tables.
First Normal Form (1NF)

Your database will be in 1NF when there are :

A primary key exists = a unique id for each row.


No repeating groups of data in each row.

Primary Key
A primary key is a field that uniquely identifies each row of the table
and cannot be null.

Add a primary key to your table

Here we will add a primary key to the spending_inital table:

First we will add a field called id and set the value of the 'id' field for
the rows that exist already, then we will set the field as a primary key.

1. Right click on the spending_initial table and select the Design option.

2. Right click on the far left column and select 'Insert Column'

3.
4. Add a column name of 'id' , data type of int and tick the checkbox to
allow nulls as shown:
5.
6. Press Ctrl+S to save the table. If you get an error check it is not being
caused by a previous database trigger.
7. Right click on the spending_initial table and select 'Edit Top 200
Rows'.
8. Update each row with a unique id field.
9. Go back to the Design of the table and right click on id column and
select 'Set Primary Key'.
10. Press Ctrl+S to save the table. Notice that when you set the id field as
a primary key the tick from the 'Allow Nulls' checkbox is removed.
11. Select the id field and then in the Column properties set the 'Identitfy
Specification' settings as shown:

12. In this example we have set the 'Identity Seed' to be 4 because we


already have rows that use the id values from 1-3.
13. Press Ctrl+S to save the table and close down any open query
windows.
Repeating Groups of Data

1. Repeated Groups means that if a field has more than one value, each
value should be placed into another table.

2. The new table should contain a primary key and this primary key
should be in the original table.
3. In the case of our spending_initial table if we had the following setup:

4.
5. You can see the row that has an id of 3, the category field has 2 values
of COFFEE and TEA. In this scenario the user might have bought
COFFEE and TEA on that day.
6. For this table to be in First Normal Form you would need to split the
category of "COFFEE TEA" into 2 rows, one with a category of
COFFEE and another with a category of TEA.
7. The result would be :
Second Normal Form
For your tables to be in second normal form they must already be in First
Normal Form before starting to remove the repeating groups of data from the
category field.

Then the following statements must also be true:

There must be no duplication of data across rows.

For example in our spending example we should not have more than 1 row
that has the same category such as 'COFFEE'. Instead where it is likely more
than one row with the same value you must:

1. Remove the categories and put them in a separate table.


For example we could create a table of categories:

2.
3. We have setup the id field using the identify specification settings so
that the id automatically increments when another category is added to
the table.

4.
5. Add a Primary key to all the rows in the new table.
Use the following statement to add the category to the new table:

INSERT INTO [dbo].[spending_category](category)

select distinct category from [dbo].[spending_initial]


6. Add a Foreign key to the original table.
7. Add a field that will be used as the foreign key for the
spending_category table into the spending_initial table.

UPDATE spending_initial

set fk_category=

(select id from [dbo].[spending_category] where


spending_initial.category=spending_category.category)

Check the data

1. Execute the following select the statements to check the results:

select * from spending_initial

select * from spending_category

2. If you are following the examples throughout this book you should see
results similar to the following screenshot:
3. Now you could remove the category field from the spending_initial
table as it is not required.
Third Normal Form

1. The database must be in the second normal form and you must remove
columns that are not dependent upon the primary key.

2. For example if there was a created_month field that contained the


month that the item was spent in the spending_initial table this could
be obtained from the created_date field.
3. In this example you do need to refer to the primary key of the id field
to find out the month the money was spent.
4. Another example would be if we had username field in the
spending_initial table because the id is referring to the id of the item
that was spent it does not make sense to have user information in this
table.
5. We would need to put these values into another table such as the
spending_users table we have already created.
6.

Other Normal forms


There are other 2 other normal forms that are not covered in this book for the
main reason that they are rarely used.

It is better to focus on the first 3 normal forms and start using them
consistently.
9. Sql Exceptions

When you start to develop more complex sql statements using more tables
and sometimes multiple databases you possible errors that might occur will
increase.

Because you cannot always predict and write code to prevent errors
occurring when statements such as SELECT or INSERT statements are run you
can define what should happen if any error occurs within a set of statements.

You will use Exception handling to define how to handle any unexpected
errors.

Exception handling consists of surrounding the parts of the program with


either TRY statements or CATCH statements.
TRY STATEMENTS - TRY Block

The TRY statements will surround the code that will run and should start
with a 'BEGIN TRY' and finish with an 'END TRY' statement.

CATCH STATEMENTS - CATCH Block

The code between the 'BEGIN CATCH' and 'END CATCH' statement will
only run when an error has occurred within the TRY block.

Below is an example of a TRY\CATCH block. This code will always fail


because dividing 1 by 0 will create an error.

--- Numeric calculation error - divide by


BEGIN TRY
PRINT 'START'
select 1/0 as result
PRINT 'END'
END TRY

BEGIN CATCH
PRINT 'ERROR'
END CATCH
RAISING AN ERROR

When you create TRY\CATCH blocks and an error occurs you will need to
alert someone to the error that occurred.

One way is to use an INSERT statement to insert a record into an audit table
as we have used in previous examples such as triggers.

Another way is to use the raiserror function as we will cover next.

Raiserror
The format of the raiserror function is:

raiserror (message_id\message string, severity,state <,optional arguments>)

message_id \ message string

The first parameter can either be a message_id from the sys.messages table
that we will cover later in the 'predefined messages' section or alternatively you
can define your own message string.

Predefined messages
To list the predefined messages you can run the following command:

select * from sys.messages

You can use this query to find predefined messages to reuse. For example if
you wanted to use the following error message ' SQL Server Audit could not
write to the security log.' you can see that the error message by running the
following query:

select * from sys.messages

where message_id=33204
Using the message_id of the error message with can run the following
raiserror function and the error message will be returned as expected:

raiserror(33204, 10,1)

returns the message: SQL Server Audit could not write to the security log.

If you use a severity of -1 the severity that is specified in sys.messages will


be used, this example a severity of 17.

raiserror(33204, -1 ,1)

returns the message:


Msg 33204, Level 17, State 1, Line 2

SQL Server Audit could not write to the security log.

Severity

Severity levels 0-18 can be used by any user whereas level 19-25 can only
be used by a sysadmin.

As you are running this logged in as the 'sa' user which has sysadmin rights
you will be able to use any severity level.
State

Use can use a state between 0 and 255.

If you use a state of -1, the state associated with the error will be used.

If the state is greater than 255 you will get an error, for example this is the
result of using a state of 300:

If use a state of 300 you will get the following error message:

Msg 2756, Level 16, State 1, Line 1

Invalid value 300 for state. Valid range is from 0 to 255.

Arguments

The arguments parameter is used to set a parameter used in the message


string.

For example if you wish to add an error number you might have the string:

raiserror('This is error number %d',16,1,44)

Msg 50000, Level 16, State 1, Line 1

This is error number 44

Within the message string use %d for a signed integer and %s for a string.

For example the statement :

raiserror('Hello %s', 1 ,1,'Mark')

Would return:
Hello Mark
Msg 50000, Level 1, State 1

10. Transactions
Next we will cover how you can encapsulate a number of statements into a
single transaction.

The purpose of using transactions is so that if there is any problem with any
of the statements in the transaction, the whole transaction will fail and any
changes that have already occurred before the statement that failed will be
reversed.

You can see how using transactions would be useful in scenarios such as
doing transfers between bank accounts where if either the debit or credit between
the two accounts involved in a transfer failed then the other transaction would
also have to be reversed.

New Keywords

The statements we will be using here are:

1. BEGIN TRANSACTION
The 'BEGIN TRANSACTION' statement indicates that the following
statements will be part of a single transaction.

2. ROLLBACK TRANSACTION
Reverse any transactions since the last 'BEGIN TRANSACTION'
statement.
3. COMMIT TRANSACTION
Save the changes since the last 'BEGIN TRANSACTION' statement.
4. @@TRANCOUNT
The number of transactions running. Running a 'BEGIN
TRANSACTION' statement will increment this value.

To print the current transaction count execute the following


statement:
PRINT @@TRANCOUNT
5. The sql statements next demonstrate the reason why we need
transactions.
You will see that first 'STATEMENT 1' is printed then , then
because an error is generated (by dividing 1 by 0) the execution jumps
to the try block and prints the 'ERROR' message.

--- Numeric calculation error - divide by

BEGIN TRY

PRINT 'STATEMENT 1'

select 1/0 as result

PRINT 'STATEMENT 2'

END TRY

--Catch block

BEGIN CATCH

PRINT 'ERROR'

END CATCH

6. If we had not used the try\catch blocks but instead had executed the
following 3 statements:

PRINT 'STATEMENT 1'

select 1/0 as result

PRINT 'STATEMENT 2'


7. The results would have been. In this case the 2 PRINT statements
have been executed but not the statement that caused the error.

STATEMENT 1

Msg 8134, Level 16, State 1, Line 2

Divide by zero error encountered.

STATEMENT 2

8. Going back to the example using the try catch block we will now
cover a more practical example using INSERT statements so that the
benefit of using transactions can be demonstrated.
9. As in the previous example when you execute the following statements
you will see that the INSERT into the spending_initial table has
worked but the second INSERT statement was not executed because of
the error.

BEGIN TRY

PRINT 'STATEMENT 1'

INSERT INTO [dbo].[spending_initial]

([created_date],[category],[amount],[user_id],[fk_category])

VALUES ('4/4/13','CLOTHES',100,2,0)

--Statement that causes an error

select 1/0 as result


PRINT 'STATEMENT 2'

INSERT INTO [dbo].[spending_audit]

([audit_category],[message],[created_dttm])

VALUES ('SPENDING','An expense has been added',GETDATE())

END TRY

BEGIN CATCH

PRINT 'ERROR'

END CATCH

10. To get this example working with transactions we need to surround the
statements in the TRY block with a BEGIN TRANSACTION (to start
a new transaction) statement and a COMMIT TRANSACTION
statement to save the changes that occurred within the transaction.

Within the CATCH block we added a ROLLBACK TRANSACTION


statement to reverse any changes made during the current transaction if an
error occurred during the TRY block.

--- Numeric calculation error - divide by

BEGIN TRY

BEGIN TRANSACTION

PRINT 'STATEMENT 1'

INSERT INTO [dbo].[spending_initial]

([created_date],[category],[amount],[user_id],[fk_category])

VALUES ('4/4/13','CLOTHES',100,2,0)
--Statement that causes an error

select 1/0 as result

PRINT 'STATEMENT 2'

INSERT INTO [dbo].[spending_audit]

([audit_category],[message],[created_dttm])

VALUES ('SPENDING','An expense has been added',GETDATE())

COMMIT TRANSACTION

END TRY

BEGIN CATCH

PRINT 'ERROR'

SELECT * FROM spending_audit

ROLLBACK TRANSACTION

END CATCH

11. The messages printed when you run this code are:

STATEMENT 1

(1 row(s) affected)

(0 row(s) affected)

ERROR

(20 row(s) affected)

The message '(1 row(s) affected)' is due to the first INSERT statement.
The message '(0 row(s) affected)' is due to the divide by 0 SELECT that caused the error and finally
the
'(20 row(s) affected)' message is cause by the SELECT statement in the CATCH block.
12. Even though the INSERT into the spending_initial table was executed
you will not see an extra row added because changes made by the
INSERT has been reversed by the 'ROLLBACK TRANSACTION'
statement in the CATCH block.
Quiz
Sql Development Objects

Section topics include - Database constraints such a primary and foreign key,
stored procedures, functions and views, triggers, synonyms, database design,
exceptions, transactions and templates.

Question 1

Why would you setup a foreign key constraint between 2 tables ?

Question 2

What is the purpose for following the rules of database design called Normal
Forms?

Question 3

Name one common use of triggers on tables\databases ?


Conculsion

Hopefully by following the examples in this book you know have a better
understanding of developing Microsoft Sql (tsql). You should now be in a
position to start creating your own examples at home and in work.

There is plenty more to learn about sql development the websites at the end
of the book will give you more information on sql server development.

Good luck with all your future developments.

Mark
Quiz Answers
Section 1. Sql Server Install and Tour

Topics - Introduction, Download and Installation of Sql Server, Sql Server


Tour

Question 1

What is the default port that sql server uses ?

Answer
1433

The reason why this is important to know is when you have a firewall
running on your computer that blocks certain ports from being access you might
need to open this port so that applications from outside the server can access sql
server.

Question 2

What are the names of the 4 system databases ?

Answer

Master, Model, Msdb and Tempdb.

Question 3

What is the difference between "Windows Authentication" and "Sql


Authentication" ?

Answer

Windows Authentication users Active Directory to check the username and


password for the login is correct whereas "Sql Authentication" checks the
password that has been setup within the sql server security for example the 'sa'
user uses "Sql Authentication".
Section 2. Starting Sql Development

Section topics include - Creating Database, Tables and Fields and first sql
queries.

Question 1

What command is used to delete a table using t-sql ?

Answer

If you just wanted to delete the data within the table you could use:

DELETE FROM <tablename>

Or if you no longer required the table you could use the DROP command:

DROP TABLE <tablename>

Question 2

What is the difference between nvarchar and varchar data types ?

Answer

The difference is that nvarchar data types can be used for unicode data that
can stored data in any language whereas varchar data types cannot store data in
all languages. So if you need your application to be truly international it is best
to use nvarchar data types.

Question 3

What command is used to find the current dateformat ?

Answer
DBCC USEROPTIONS will return the current dateformat.
Section 3. Advanced Queries

Section Topics - Introduction, Download and Installation of Sql Server, Sql


Server Tour

Question 1

1. Why will this statement cause an error ?

SELECT SUM(amount) as total , user_id from spending_initial

GROUP BY category

Answer

The error message is:

Msg 8120, Level 16, State 1, Line 1

Column 'spending_initial.user_id' is invalid in the select list because it is not


contained in either an aggregate function or the GROUP BY clause.

The following statement would correctly group the amount field totals by
category:

SELECT SUM(amount) as total , category from spending_initial

GROUP BY category

Question 2

How would to remove whitespace from the left and right side of a string?

Answer

There is no single function that removes whitespace from the left and right
side of a string at the same time. Therefore you need to use the functions
LTRIM and RTRIM together, for example:
select '*' + LTRIM(RTRIM(' please trim this string '))+'*'

I added the '*' so it is easier to see the whitespace has been removed and the
result should be:

*please trim this string*


Question 3

Which Conditional statement can be used in a SELECT statement ?

Answer

Within a SELECT statement you can use a CASE statement, for example:

SELECT (CASE
WHEN DATEPART(month,GETDATE())>6 THEN
'Second half of year'
ELSE
'First half of year'
END) as half_of_year
Section 4. Sql Development Objects

Section topics include - Database constraints such a primary and foreign key,
stored procedures, functions and views, triggers, synonyms, database design,
exceptions, transactions and templates.

Question 1

Why would you setup a foreign key constraint between 2 tables ?

Answer
You would setup a foreign key constraint to maintain the integrity of the data
between 2 tables. So in the example used in this book that would mean that only
user_id's that existed in the spending_users table could have entries in the
spending_initial table.

Question 2

What is the purpose for following the rules of database design called Normal
Forms?

Answer
The main purpose of following the normal forms is to reduce the duplication of
data within your tables and make the data easier to maintain.
Question 3

Name one common use of triggers on tables\databases ?

Answer
The most common use for triggers is maintain an audit of actions on
tables\databases.
Useful Websites

Microsoft Sql Server Websites

http://techstuffy.com

This is the website will all updates and related information for this
book such as sample data.

http://Microsoft.com/sqlserver

http://sqlservercentral.com

Useful for all things sql server related.

You might also like