Practical SQL: Microsoft SQL Server T-SQL for Beginners [Paperback ed.] 1492753408, 9781492753407

http: //practical-sql.com Practical Sql - Microsoft Sql Server T-SQL for Beginners Learning how to develop using sql or

1,623 260 2MB

English Pages 212 Year 2013

Report DMCA / Copyright

DOWNLOAD FILE

Polecaj historie

Practical SQL: Microsoft SQL Server T-SQL for Beginners [Paperback ed.]
 1492753408, 9781492753407

Citation preview

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. 2. 3.





Once the download has completed double click on the file to start the installation. Click the Installation menu option on the left hand side of the screen and then select 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. 6.

Click Install SSMS and download the current version of the SSMS. 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. 4.

Go to Sql Server Services , right click on the SQL Server and select restart. 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 Server\MSSQL14.SQLEXPRESS\MSSQL\DATA\ Log

SQL

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

SQL

SQL

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. 2.

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

Server type: Database Engine Server name: .\SQLEXPRESS Authentication: Windows Authentication 3. 4.

5.

Click Connect. You should now be connected to the installation of sql server. To Disconnect from sql server right click on the icon .\SQLEXPRESS in the object explorer and select disconnect.

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 Server\MSSQL14.SQLEXPRESS\MSSQL\DATA

SQL

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. 4. 5. 6.

In the Management Studio expand the database you created and right click on the Tables folder and select the Table… option. 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. A null value means that you do not have to fill in the field. 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. 2.

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. 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.

4.

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. 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:

10.

DROP TABLE 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. The format for the CONVERT function is:

2.

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 select CONVERT(varchar(10), GETDATE(), 103)

4.

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 ‘ddMM-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. 4. 5. 6. 7.

8.

Open a 'New Query' window and check the dateformat using the DBCC USEROPTIONS command. You will see it is mdy and the dateformat does not change for all sessions. If you change the default language of the login that date format will change for all sessions. Open the security folder, logins , right click on your login and select properties. 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’. 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( as ) 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(,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(,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:

2.

INSERT INTO

([list of fields]) VALUES () 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. 5.

This will display the same results as the command generated by the gui. 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 INTO FROM
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. Next we will cover how to update rows in the table using the tsql UPDATE statement. For basic format of the UPDATE statement is:



3. 4.

UPDATE
SET = WHERE = 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. 8.

9. 10.

In this example we have added a WHERE clause. 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'. If we did not include the WHERE clause all the rows in the table would have their category field set to 'FOOD'. 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
[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. 2. 3. 4.

Group Data Manipulate strings Total numeric fields in a table 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' : 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 ) 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() 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. 3.

Changing strings like pathnames\servernames in strings. 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 BEGIN

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 BEGIN

END ELSE BEGIN

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 THEN END) as FROM 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. 3. 4.

Add a field to the [dbo].[spending_initial] table. To do this right click on the table and select design. Add the field user_id with a data type of int, leave the tick in the 'Allow Nulls' box. 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.

6. 7.

8.



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

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. 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 FROM INNER JOIN ON = 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. 6. 7.

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. 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. 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. When you edit the spending_initial table the table should look something like from the following screenshot:



3.

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.

6.

You will get the result:

7. 8.

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. 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. 4. 5. 6. 7. 8.

Right click on the Constraints folder and select the 'New Constraint' option... Click on the Expression field and enter the following expression: budget 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. 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. Press Ctrl+S to save the table and select 'Yes' to any warnings. 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.

12.

13. 14.



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. 3.

Right click on the spending_users table and select Design. Right click on the user_id field and select 'Set Primary Key'. A key symbol will appear to the left of the field name. Press Ctrl+S to save the changes to the table. 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.



4. 5.

6. 7. 8.

Once you have saved the table without any errors, close the design window. Right click on the spending_users table and select 'Edit Top 200 Rows'. 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. Next we will setup a foreign key in the spending_initial table and test the constraint.



3.

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. 3.

Right click on spending_initial table and select the Design option. 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 Click on the OK button Expand the 'INSERT And UPDATE Specification' option. Notice that the settings for the 'Delete Rule' and 'Update Rule' options are set to 'No Action'.









8. 9.



10. 11. 12.

Click on the Close button. Press Ctrl+S to save the table changes. You will get the following warning:

13. 14.

Click on the Yes button to continue. 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. 3. 4.

Right click on the Foreign key and select Modify. The 'Foreign Key Relationships' box will be displayed. Expand the 'INSERT And UPDATE Specification' option. Notice that the settings for the 'Delete Rule' and 'Update Rule' options are set to 'No Action'. Select the 'Delete Rule' option and choose 'Cascade' from the dropdownlist.

Click on the Close button. Press Ctrl+S to save the table and 'Yes' to continue.



5.

6. 7.

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'. Highlight the row with user_id 1 Press the delete key and press the Yes button when you get the following warning:



3. 4.

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. 3. 4. 5. 6. 7. 8.

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



9. 10. 11. 12.

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.

15.



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. 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. Remind you to fill in various details such as Author name, create date and descriptions which might be overlooked. To view some of the many templates that are available to the user select the View->Template Explorer option.



3. 4.

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. 8.

Double click on the 'Create Procedure Basic Template' option to open the template in a new query window. 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\\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. 4.

Rename the folder 'my templates'. Right click on the folder and select New->Template The new template is created in:

5. 6. 7.

C:\Users\\AppData\Roaming\Microsoft\SQL Server Management Studio\14.0\Templates\Sql\my templates Rename the new template 'my_first_template'. Double click on the new template and a query window will be opened. Within the new query window add the following statement:

SELECT * from [dbo].[spending_initial]

8.

The format for adding parameters to a template is:

9.

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

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=



11. 12. 13.

To edit this template simply right click on the template name and select edit. To access the Template parameters quickly select Alt+Q, then S. 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. 2.

Open a 'New Query' window. 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: CREATE PROCEDURE dbo.Sample_Procedure @param1 int = 0, @param2 int









5.

AS SELECT @param1,@param2 RETURN 0

6.

The snippets are stored in the following folder:

C:\Program Files (x86)\Microsoft Server\140\Tools\Binn\ManagementStudio\SQL\Snippets\1033

SQL

7. 8. 9. 10. 11.

To add your own snippet you can add a .snippet file to the following folder: C:\Users\\Documents\SQL Server Management Studio\Code Snippets\SQL\My Code Snippets. Within the SSMS go to the Tools->Code Snippets Manager. Then click Add and select your My Code Snippets folder. The snippet will then be available within the My Code Snippets folder. 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:









Title Description Author ToolTip







My Test Snippet title

My Test snippet Mark ODonovan

Expansion







My Test tsql code









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. 3.

Expand the database folder, then the Programmability folder. 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: -- Create date: -- Description:

-- ============================================= CREATE PROCEDURE ProcedureName>

10

UNION

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

WHERE amount>10

5. 6.

Execute the stored procedure by clicking the Execute button or Alt+X. 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 ' part of the statement, for example: ALTER PROCEDURE [dbo].[usp_myfirstsp]

(

@filter_category varchar(20)

)

......

8. 9.

If you required more than one stored procedure these would be separated by a comma. All parameters must start with a @ symbol.

The format of the parameter is: @ 10. 11.

Next add the parameter @filter_category to our example stored procedure as shown in the above example. 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. 14.

Press Alt+X to make the changes to the stored procedure. 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.

18. 19. 20.

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. Open a new query window by clicking the new query button. Run the stored procedure as: exec [dbo].[usp_myfirstsp] 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.

22. 23.

24. 25.

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

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

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. 2. 3. 4. 5. 6.

All tables must be in the same database. Any user-defined functions referenced in the view must have been created with the SCHEMABINDING option as well. The AVG, MAX, MIN aggregate functions aren’t allowed in the SELECT statement. You can’t use UNION, TOP, ORDER BY, DISTINCT, COUNT(*) If you would aggregate functions in a view you can use it to update data. 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. There are 4 tabs in the 'Add table' dialog which are:







4.

5. 6.

Tables Views Functions Synonyms Click the Close button on the 'Add Table' dialog and we are going to create the SELECT statement using tsql. 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. 8.

Press Ctrl+S to save the view, set the name of the view to 'spending_all' and press the OK button. 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. 3.

Click the OK button on warning dialog box. Change the select statement to:



SELECT created_date, category, amount, user_id FROM dbo.spending_initial 4. 5.

Press Ctrl+S to save the view. 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.

7.

8.

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. You cannot update a view if the select uses any of the following keywords UNION, UNION ALL, CROSSJOIN, EXCEPT, and INTERSECT. 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:

4.

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

5. 6. 7.

Msg 3729, Level 16, State 1, Line 7 Cannot DROP TABLE 'spending_initial' because it is being referenced by object 'spending_all_bound'. Right click on the view spending_all_bound and select Delete. Click the OK button from the 'Delete Object' dialog box. Run the following command to make a backup of the spending_initial

table:

8.

9.

select * into spending_initial_bak from spending_initial Now run the DROP statement again and this time it will work without an error: DROP TABLE [spending_initial] 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. The query that we will use in the function is:



3.

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

7.

8. 9.

10. 11. 12.

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

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

Delete the comments at the top of the template and press Ctrl+S to save the script. 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)

15.

Declare 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.

17.

The SELECT statement will be used to set the value you have just defined (@budgettotal). Set the variable using the format = in the field list of the SELECT statement. 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. 23.

To execute this function within a select statement, open a new query window. Type the following statement: select dbo.fn_budget_total()

24. 25.

Press Alt+X to the execute statement and you should get the total returned. 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. The script to update this function should be:



3.

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. 5.

As we do not have a default value for this function if you try to run the following SELECT statement: 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.

9. 10. 11.



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 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. The power of functions comes from combining them with results returned from other SELECT statements. 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. 5.

6.

The template for the inline table-valued function will be displayed in a new query window. Select the menu option Query->Specify Values for Template Parameters.. or press Alt+Q,S. 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. Your script should now look like the following text:

8.

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. 10.

Before continuing save the current script. 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:

14.

SELECT * FROM dbo.fn_dept_users('IT') 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. 3.

In this statement first we have setup a single parameter for the user_id. 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. 5. 6.

Next we define the variables that will be used to store the results of the SELECT statements. DECLARE @username varchar(40), @category varchar(20), @amount numeric(5,2) 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.

10. 11. 12.



We can execute this function just like the inline table-valued function using the following statement: select * from fn_getuser_spending('2') This query returns the following result:

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
FOR 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.

3.

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. 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. 5.

The IDENTITY function allows you to create an integer field that automatically increments when each row is added to the table. The first parameter is the starting number and the second parameter

6.

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. 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.

2.

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. Expand the spending_initial table.

3.

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

4. 5.

The template for the trigger will appear in a new query window. 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. 10. 11.

Press Alt+X or the Execute button to create the trigger object in the database. Expand the triggers folder to check that the trigger now exists. 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 ON DATABASE FOR 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.

3. 4.

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. 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. 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. 8. 9.

If you run a SELECT statement on the spending_audit table will find a row has been added to the table. Other DDL events you might want to create triggers for are DROP_TABLE and ALTER_TABLE instead CREATE_TABLE. 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 ON 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.

4.



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. 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.

3. 4. 5.

6.

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. 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. Next we will cover the 'INSTEAD OF' type of trigger. 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. 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. 10. 11.



Press Alt+X to create this trigger in the database. Right click on the spending_users table and select 'Edit Top 200 Rows'. 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. 13.

Now press the execute button to refresh the data and you will see that the row you have just entered disappears. 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.

5.

6.

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. 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. 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. 7. 8. 9. 10. 11.

Press Ctrl+S to save the table. If you get an error check it is not being caused by a previous database trigger. Right click on the spending_initial table and select 'Edit Top 200 Rows'. Update each row with a unique id field. Go back to the Design of the table and right click on id column and select 'Set Primary Key'. 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. Select the id field and then in the Column properties set the 'Identitfy Specification' settings as shown:



12. 13.

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. 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. In the case of our spending_initial table if we had the following setup:



3.

4. 5.

6.

7.

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. 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. 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.

4. 5.

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.

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. 7.

Add a Foreign key to the original table. 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] spending_initial.category=spending_category.category)

where

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. 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. 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. We would need to put these values into another table such as the spending_users table we have already created.



3. 4.

5. 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 ) 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. COMMIT TRANSACTION Save the changes since the last 'BEGIN TRANSACTION' statement. @@TRANCOUNT The number of transactions running. Running a 'BEGIN TRANSACTION' statement will increment this value.



3. 4.

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.

9.

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. 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 Or if you no longer required the table you could use the DROP command: DROP TABLE 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.