Simple SQL Tutorials User Defined Functions
Simple SQL Tutorials User Defined Functions
Defined Functions
A complete guide on creating and using user
defined functions in Microsoft SQL Server
www.SimpleSQLTutorials.com
All rights reserved. No portion of this book may be reproduced or redistributed in any form by any means
without expressed written permission from the author, Joshua Decker of SimpleSQLTutorials.com.
This book is provided "as-is". It expresses the views and opinions of the author. The views, opinions, and
information referenced in this book, including URL and other internet website references, may change
without notice.
The information referenced in this book, including names, locations, and businesses is purely fictional and
any references to actual names, locations, and businesses are purely coincidental. No real association or
connection is intended, nor should any real association or connection be inferred.
The integrity and accuracy of the reader's data is solely the responsibility of the reader. The author has
made every effort to ensure the accuracy of the information within this book was correct at time of
publication. The author does not assume and hereby disclaims any liability to any party for any loss,
damage, or disruption caused by errors or omissions, whether such errors or omissions result from
accident, negligence, or any other cause.
http://simplesqltutorials.com/simple-sql-tutorials-data/
On this page, you can download a backup of a database called SimpleSQLTutorialsData and restore that
database to your local SQL Server. The backup was created in a Microsoft SQL Server 2019
environment.
If you would rather not restore a database, or are having trouble restoring the database, this webpage also
contains the statements necessary to manually add the data to your environment. It is still strongly
recommended that the data be created in an entirely new testing database, and all testing be performed
against this separate testing database.
Table of contents
Introduction ................................................................................................................................................................................................................ 1
Conclusion ................................................................................................................................................................................................................. 14
Introduction
Thank you for choosing Simple SQL Tutorials as your source for T-SQL training!.
User defined functions are a very useful tool we have available to us in Microsoft SQL Server. If you are
trying to learn about them and understand how they work, you should congratulate yourself because you
are leveling up!
If you come from a programming background, you might be familiar with the idea of a "function". But
honestly, the concept of user defined functions in SQL Server is dissimilar to functions in a traditional
programming language. You should approach the idea of user defined functions in SQL Server with an
open mind.
There are two types of user defined functions that can be used to return the result set of an inner query to
the caller, and another that returns a single value to the caller. For those functions that return a result set,
they can be called anywhere a result set is expected, such as in a FROM clause or an INNER JOIN clause.
For the function type that returns a single value, it can be called anywhere a single value is expected, such
as on one side of a WHERE clause.
We will learn all about the different types of functions in this book and provide simple, thorough
explanations to help you understand. By the time you finish this book, you will have a very solid
understanding of user defined functions in SQL Server.
Page 1
Chapter 1
Inline Table Valued Functions
Inline Table Valued Functions (or just "inline functions" for short) can be used to store a complicated query
as an object in the database, which then allows us to execute that query using very simple commands.
Inline functions (and also multi statement functions) are similar to another object commonly used in
Microsoft SQL Server called a "View". A View is another tool we can use to store a complicated query
easily in the database. Learn more: https://simplesqltutorials.com/sql-server-view/
One major difference between a View and inline functions is that inline functions give us the ability to store
a dynamic query via input parameters. The result set returned from the inner query may be different
depending on what input parameters are passed in.
<schema> : You are not required to put a schema name. If you leave off the schema name, the
function will be put in the dbo schema by default.
<optional_parameters> : You aren't required to pass in parameters to an inline function, but normally
the whole reason you would want to create an inline function is because you want to make it dynamic
via input parameters.
The RETURNS TABLE keyword : An inline function returns a result set, and the way we outline that
we want to return a result set is to use the RETURNS TABLE keyword.
The RETURN clause : Every function needs a RETURN clause. This basically passes the result set
back to the caller of the function. You just put the "RETURN" keyword before your inner query.
<inner query> : As mentioned earlier, an inline function will return a result set. The result set returned
is the result set generated by this inner query. This is very similar to a View.
We'll work through some examples to better understand inline functions. Take a look at the following query
that gives us a breakdown of all the products that have been purchased for a specific customer:
Page 2
Chapter 1 - Inline Table Valued Functions
The way we isolate orders for a specific customer is by outlining the customer's ID in the WHERE clause. If
we wanted to see details for a different customer, all we need to do is specify a different ID:
This can be a very helpful query if we want to know the order history for a specific customer. It would be
great to save this query as an object in the database, but we can't save it as a View because there is
obviously a dynamic element to it. Instead, we can save it as an inline function:
Page 3
Chapter 1 - Inline Table Valued Functions
There are a few key items we need to understand about this function. First, notice we did not outline a
schema name alongside the name of the function. Because we didn't outline a schema, the function
defaults to being within the dbo schema. This will be important to remember later when we attempt to call
the function.
Second, notice our input parameter is just a variable. We always use the '@' symbol to identify a variable,
and it must include a data type. You aren't limited in the number of input parameters you can have either
(well, actually, there is a limit. It's 2,100).
Third, the columns in our inner query must all be named. For example, we have a derived column using the
CONCAT function that appends a person's first and last name together. This derived column needed to be
given an alias.
Lastly, the inner query is nearly identical to the query we ran a minute ago except for the WHERE clause.
Instead of a hard-coded customer ID, we outline the input parameter. When we call this function, the value
stored in that input parameter will be used to filter the result set.
If we run this CREATE FUNCTION statement, we can see the new function in our object explorer under
Programmability | Functions | Table-valued Functions:
We can call our inline function any place a result set is expected, such as in a FROM clause or in a JOIN
clause. Here is an example of calling the function in a FROM clause:
The first thing you should notice is that we outlined the schema the function belongs to. Remember, when
we created the function, we did not specify a schema which means the function defaulted to being within
the dbo schema. When we call any function, we need to outline the schema it belongs to.
Page 4
Chapter 1 - Inline Table Valued Functions
Then of course we have the function name and the CustomerID in parentheses that we would like to pass
to the function. Of course, if we wanted to see the breakdown for a different customer, all we need to do is
pass the appropriate CustomerID:
So easy! Again, when the function is executed, the @customerID parameter is given the value that is
passed in the call. The inner query then uses that value, generates a result set, and returns that result set
back to the caller.
Notice we still need to use parentheses after our function name, even though they are empty.
Page 5
Chapter 1 - Inline Table Valued Functions
Once again, we still need to use parentheses when we call the function even though there are no
parameters.
Folks, creating a parameter-less function would be a weird thing to do. If you think about it, we just created
a funny-looking View, right? The inner query of this function is now static, just like it would be for a View.
The whole reason you would create an inline function instead of a View is because you want the inner
query to be dynamic via input parameters. If you don't want parameters, you should choose to make your
object a View instead!
Notice we don't need to specify the schema name when we drop a function. You would only need to specify
a schema if you have two functions named exactly the same but in different schemas. We also don't need
to use parentheses when we drop a function.
Page 6
Chapter 2
Multi Statement Table Valued Functions
We can also create Multi Statement Table Valued Functions (or "multi statement functions" for short) as
permanent objects in the database. They also store an inner query and return a result set to the caller. Multi
statement functions give us more control over the result set that is returned.
This syntax can seem a bit complicated, but it's actually very easy once you break down the parts and
understand what's happening. Here is how a multi statement function works in a sentence:
Multi statement functions return the result set of a table variable that is defined and populated
within the definition of the function.
In the definition of the function, notice the first thing we do is create a table variable. We have complete
control over this table variable, including the column names, their data types, the nullability of columns,
indexes, constraints, etc.! This level of control is what makes multi statement functions more powerful than
inline functions.
In the body of the function, all we need to do is make sure we populate the table variable. This basically
means the body can have more than just a single inner query. In a multi statement function, you can do
many things. For example, you can have several queries if you need them, or decision structures, or loops,
etc.! At the end of the day, you just need to make sure your table variable is populated because the content
of that table variable is what will be returned to the caller.
Let's look at a simple example. We'll re-create our OrderDetailsByCustomer function but make it a multi
statement function:
Page 7
Chapter 2 - Multi Statement Table Valued Functions
RETURN
END
Notice I chose to explicitly outline the schema this time. Also notice the definition of the inner table variable
and how we gave it indexes to help our queries perform much faster. Again, things like this are what make
multi statement functions so powerful. We have complete control over the table variable definition and can
use objects and tools that can dramatically increase the performance of our queries to this function.
This isn't any different from what we discussed with inline functions. You always need to outline the schema
to which the function belongs, and you use parentheses around your input parameter(s).
Also like we talked about with inline functions, your multi statement functions don't need to have
parameters. I talked about how it would be strange to have an inline function without parameters, but in the
case of multi statement functions, I think it's perfectly reasonable to create one without parameters. One
might do this to take advantage of the level of control you have over the inner table variable, like how you
can create indexes in the table variable. These indexes might help your inner query perform faster than it
would outside of the function.
It all comes down to the level of control you have in a multi statement function since YOU create and define
the inner table variable. As we've discussed, objects like indexes, constraint etc. can be extremely helpful
for query performance and data integrity.
To demonstrate the use of the clustered index we made on our table variable, we can look at the query
execution plan for the query we just ran. We need to enable the 'Include Actual Execution Plan' button in
SQL Server Management Studio:
Page 8
Chapter 2 - Multi Statement Table Valued Functions
Then we'll run our query again, and click on the "Execution Plan" tab that appears:
The use of the clustered index will drastically speed up queries to this function. Want to learn more about
indexes? Follow these links:
http://www.SimpleSQLTutorials.com/sql-server-clustered-index
http://www.SimpleSQLTutorials.com/nonclustered-index-guide-for-beginners
Page 9
Chapter 3
Scalar Valued Functions
Scalar Valued Functions (or just "scalar functions" for short) are different from inline functions and multi
statement functions in that they do not return a result set.
Scalar functions return a single value back to the caller (the word "scalar" is just another word for "single").
Scalar functions can be used anywhere a single value is expected, such as in the column list of a SELECT
statement or on one side of a WHERE clause.
In the RETURNS clause at the top of the function, we outline the data type of the scalar value that will be
returned to the caller. The body of the function can be anything you need it to be. At the end of the day, it
just needs to derive a single value that will be returned to the caller. We return that value using the
RETURN statement at the end of the function.
Here's an example of a scalar function that figures out how much income we've made for a specific
customer and returns that value back to the caller:
CREATE OR ALTER FUNCTION IncomeFromCustomer(@customerID INT)
RETURNS DECIMAL(6,2)
AS
BEGIN
DECLARE @income DECIMAL(6,2)
RETURN @income
END
Page 10
Chapter 3 - Scalar Valued Functions
So it looks like we've made $463.20 from customer # 50, who is Joshua Porter. If we wanted to see the
income from a different customer, we just need to change the ID we pass to the function:
Here's another example of a scalar function that figures out the ID of the customer who has purchased the
most products from us:
RETURN @CID
END
This function uses a derived table and the TOP tool to help us figure out the ID of our best customer. We
then return that value to the caller. Here is what a call to this function could look like:
This query returns some basic contact information about our best customer. The nice thing about this
function and query is how we don't need to change it at all to see details about our best-selling customer,
whoever that may be. Right now, our best customer is Gordon Acres, but next week it might be someone
else. To see those details about the new best-selling customer, we just run exactly the same query!
Page 11
Chapter 3 - Scalar Valued Functions
Page 12
Chapter 4
Limitations on Functions
The things you can do inside a function are not limitless. There are a few things you cannot do inside the
definition of a function:
You cannot have error handling code in your function. You cannot use TRY...CATCH blocks, for
example.
You cannot create or use temporary tables within a function. A temp table is created using the CREATE
TABLE statement and a '#' symbol in front of the name. For example:
You cannot use dynamic SQL within the definition of a function. Dynamic SQL is when you write a SQL
command as a string literal and call the 'EXECUTE' system function on that string literal. For example,
you cannot say EXECUTE 'SELECT ProductName FROM Products' from within a function.
You cannot use Data Definition Language inside a function, which are basically CREATE, ALTER, or
DROP statements. You couldn't make a new table from within a function if you wanted to, for example.
The exception is multi statement functions where you create an inner table variable.
Data manipulation is not allowed in a function. You cannot run INSERT, UPDATE, or DELETE
statements from within a function. The only exception is if you were inserting, updating, or deleting data
in a table variable, which is exactly what we do with multi statement functions.
Page 13
Conclusion
Thank you very much for choosing Simple SQL Tutorials as your source for T-SQL training!
I hope the knowledge you've gained from this book will give you the confidence and skill you need to further
your career in data and better your situation.
As you've learned, user defined functions can be very complex. If you are trying to learn about them and
understand the different user functions available to us in Microsoft SQL Server, you should congratulate
yourself because you are leveling up! I hope this book has given you the knowledge needed to perform
your job well and add value to yourself and your company.
A bit about me
My name is Josh, and I have been working with
databases as an Application Developer for over 10
years.
My goal with Simple SQL Tutorials is to offer that simplified, accurate training I wish I had, while also
breaking down these complicated SQL Server topics into terms that are easy to understand.
Thank you again for reading! Please don’t hesitate to contact me (SimpleSQLTutorials.com/Contact) if
you have questions.
Page 14