SQL Server Handy Notes VishwanathReddy
SQL Server Handy Notes VishwanathReddy
Master
o Purpose - Core system database to manage the SQL Server instance. In SQL Server 2005,
the Master database is the logical repository for the system objects residing in the sys
schema. In SQL Server 2000 and previous editions of SQL Server, the Master database
physically stored all of the system objects.
o Prominent Functionality
Per instance configurations
Databases residing on the instance
Files for each database
Logins
Linked\Remote servers
Endpoints
o Additional Information
The first database in the SQL Server startup process
In SQL Server 2005, needs to reside in the same directory as the Resource
database
TempDB
o Purpose - Temporary database to store temporary tables (#temptable or ##temptable),
table variables, cursors, work tables, row versioning, create or rebuild indexes sorted in
TempDB, etc. Each time the SQL Server instance is restarted all objects in this database
are destroyed, so permanent objects cannot be created in this database.
o Prominent Functionality
Manage temporary objects listed in the purpose above
o Additional Information
Properly Sizing the TempDB Database
Each time a SQL Server instance is rebooted, the TempDB database is reset to its
original state
Model
o Purpose - Template database for all user defined databases
o Prominent Functionality
Objects
Columns
Users
o Additional Information
User defined tables, stored procedures, user defined data types, etc can be
created in the Model database and will exist in all future user defined databases
The database configurations such as the recovery model for the Model database
are applied to future user defined databases
MSDB
o Purpose - Primary database to manage the SQL Server Agent configurations
o Prominent Functionality
SQL Server Agent Jobs, Operators and Alerts
DTS Package storage in SQL Server 7.0 and 2000
SSIS Package storage in SQL Server 2005
o Additional Information
Provides some of the configurations for the SQL Server Agent service
For the SQL Server 2005 Express edition installations, even though the SQL Server
Agent service does not exist, the instance still has the MSDB database
Missing SQL Server Agent History
MSSQLTips Category - SQL Server Agent
Data Access - Based on the version of SQL Server query only the recommended objects. In
general the system database objects are being deprecated to a set of views, so be sure all of your
scripts are accessing the right objects. If not, you are going to have a big project in the future to
convert all of your scripts.
Changing Objects - Do not change system objects. In SQL Server 2005 all of the database objects
have been moved to the Resource database which stores the definition for the system objects
and can be updated via new SQL Server releases independent of the data.
New Objects - Creating objects in the system databases is not recommended. If you have
objects that are needed for the instance i.e. administrative items, just create a separate DBA
database to store these objects.
Sneaking a Peak - Up to this point, all of the T-SQL code for the tables, views, stored procedures,
functions, etc. has been clear text. So you can review the objects and learn from the techniques
used by Microsoft.
Dropping Objects - The most prominent reason to drop system objects are for specific types of
lock downs and auditing in particular industries. Although some of those practices are well
documented, be sure you understand the ramifications related to administering and developing
applications once those restrictions are in place.
Security - Do not forget about the Public role and Guest user, they are the conduit for users to
access the system objects. So that should answer the question of how people (logins\users) can
access the objects based on the object owner or schema, depending on the SQL Server version.
Backups - Be sure to have a consistent backup process for your system databases. Including the
system databases with your user defined databases might be the best approach if a disaster
occurs.
Scope - Each SQL Server instance (including the Express Edition) has its own set of SQL Server
system databases. As such, if a single Windows server has multiple SQL Server instances
installed, a change to one system database only impacts the single instance, not all instances on
the Windows server.
String types:
Number types:
Date types:
SQL Commands
SQL commands are instructions used to communicate with the database to perform specific task that
work with data. SQL commands can be used not only for searching the database but also to perform
various other functions like, for example, you can create tables, add data to tables, or modify data, drop
the table, set permissions for users. SQL commands are grouped into 4 major categories depending on
their functionality:
Data Definition Language (DDL) is a standard for commands that define the different structures in a
database. It is used to create and modify the structure of database objects in the database.
It is used to retrieve, store, modify, delete, insert and update data in database.
SELECT – Retrieves data from a table
INSERT - Inserts data into a table
UPDATE – Updates existing data into a table
DELETE – Deletes all records from a table.
Filter Clause
WHERE clause ensures the data is filtered when it is retrieved in select statements or it ensures only
those records are affected when updating / deleting is performed. WHERE clause can be used in Select,
Update, Delete statements to filter the rows being affected by the query.
The conditions in WHERE clause can be based on one or more operators and the operators that can be
used in a WHERE clause can be =, <>, != , >, <, BETWEEN, IN, LIKE, NOT and many more. When there
are multiple conditions, those conditions can be combined with AND / OR.
GROUP BY Clause
The GROUP BY clause is used to aggregate information. The GROUP BY statement is used in conjunction
with the aggregate functions to group the result-set by one or more columns.
Having Clause: Specifies a search condition for a group or an aggregate. HAVING is usually used with
the GROUP BY clause.
HAVING specifies a search condition for a group or an aggregate function used in SELECT statement.
HAVING can be used only with the SELECT statement. HAVING is typically used in a GROUP BY clause.
When GROUP BY is not used, HAVING behaves like a WHERE clause.
The HAVING clause was added to SQL because the WHERE keyword could not be used with aggregate
functions.
The ORDER BY keyword sorts the records in ascending order by default. To sort the records in a
descending order, you can use the DESC keyword. Specifies the sort order for the result set. The ORDER
BY clause is not valid in sub-queries. Specifies a column on which to sort. A sort column can be specified
as a name or column alias, which can be qualified by the table name, or an expression. Multiple sort
columns can be specified. The sequence of the sort columns in the ORDER BY clause defines the
organization of the sorted result set. Columns of data type ntext and image cannot be used in an
ORDER BY clause.
ASC: Specifies that the values in the specified column should be sorted in ascending order, from lowest
value to highest value.
DESC: Specifies that the values in the specified column should be sorted in descending order, from
highest value to lowest value. Null values are treated as the lowest possible values.
Order By clause does not work in View. ORDER BY should be used outside the View and not in the View
It is always recommended to use proper ORDER BY clause with ColumnName to avoid any confusion.
Operators: http://technet.microsoft.com/en-us/library/ms174986.aspx
Comparison operators test whether two expressions are the same. Comparison operators can be used
on all expressions except expressions of the text, ntext, or image data types. The following table lists
the Transact-SQL comparison operators.
Operator Meaning
= (Equals) Equal to
> (Greater Than) Greater than
< (Less Than) Less than
>= (Greater Than or Equal To) Greater than or equal to
<= (Less Than or Equal To) Less than or equal to
<> (Not Equal To) Not equal to
!= (Not Equal To) Not equal to (not ISO standard)
!< (Not Less Than) Not less than (not ISO standard)
!> (Not Greater Than) Not greater than (not ISO standard)
Logical Operators: Logical operators test for the truth of some condition. Logical operators
Search expressions:
SQL wildcards are used to search for data within a table.
% A substitute for zero or more characters
_ A substitute for a single character
[charlist] Sets and ranges of characters to match
[^charlist] or [!charlist] Matches only a character NOT specified within the brackets
Bitwise Operators
Bitwise operators perform bit manipulations between two expressions of any of the data types of the
integer data type category.
Operator Meaning
& (Bitwise AND) Bitwise AND (two operands).
| (Bitwise OR) Bitwise OR (two operands).
^ (Bitwise Exclusive OR) Bitwise exclusive OR (two operands).
The operands for bitwise operators can be any one of the data types of the integer or binary string data
type categories (except for the image data type), except that both operands cannot be any one of the
data types of the binary string data type category. The following table shows the supported operand
data types.
Range Operators:
IN/NOT IN:
IN: Determines whether a specified value matches any value in a subquery or a list.
NOT IN: Determines whether a specified value does not match any value in a subquery or a list.
BETWEEN: Specifies a range to test, The BETWEEN operator is used to select values within a range. The
BETWEEN operator selects values within a range. The values can be numbers, text, or dates. :
test_expression [ NOT ] BETWEEN begin_expression AND end_expression.
Set Operators: SQL Server provides the following set operators. Set operators combine results from two
or more queries into a single result set.
UNION: Combines the results of two or more queries into a single result set that includes all the rows
that belong to all queries in the union. The UNION operation is different from using joins that combine
columns from two tables.
The following are basic rules for combining the result sets of two queries by using UNION:
The number and the order of the columns must be the same in all queries.
The data types must be compatible.
UNION ALL: Incorporates all rows into the results. This includes duplicates. If not specified, duplicate
rows are removed. ORDER BY clause should be used only on the last SELECT statement in the UNION query.
EXCEPT and INTERSECT: Returns distinct values by comparing the results of two queries.
EXCEPT returns any distinct values from the left query that are not also found on the right query.
INTERSECT returns any distinct values that are returned by both the query on the left and right sides of
the INTERSECT operand.
The basic rules for combining the result sets of two queries that use EXCEPT or INTERSECT are the
following:
The number and the order of the columns must be the same in all queries.
The data types must be compatible.
Aggregate Functions:
Aggregate functions perform a calculation on a set of values and return a single value. With the
exception of COUNT, aggregate functions ignore null values. Aggregate functions are often used with
the GROUP BY clause of the SELECT statement.
Aggregate functions are allowed as expressions only in:
The select list of a SELECT statement (either a subquery or an outer query).
A COMPUTE or COMPUTE BY clause.
A HAVING clause.
The Transact-SQL programming language provides these aggregate functions:
AVG MAX
BINARY_CHECKSUM MIN
CHECKSUM SUM
CHECKSUM_AGG STDEV
COUNT STDEVP
COUNT_BIG VAR
GROUPING VARP
String Function:
These scalar functions perform an operation on a string input value and return a string or numeric
value.
All built-in string functions, except for CHARINDEX and PATINDEX, are deterministic. They return the
same value any time they are called with a given set of input values.
Date and Time Functions
These scalar functions perform an operation on a date and time input value and return a string,
numeric, or date and time value.
This table lists the date and time functions and their determinism property. For more information about
function determinism.
Function Determinism
DATEADD Deterministic
DATEDIFF Deterministic
DATENAME Nondeterministic
DATEPART Deterministic except when used as DATEPART (dw, date).
dw, the weekday datepart, depends on the value set by SET
DATEFIRST, which sets the first day of the week.
DAY Deterministic
GETDATE Nondeterministic
GETUTCDATE Nondeterministic
MONTH Deterministic
YEAR Deterministic
Column and Table Alias: SQL aliases are used to temporarily rename a table or a column heading.
Aliases can be useful when:
INTO Clause
SELECT…INTO creates a new table in the default filegroup and inserts the resulting rows from the query
into it.
SELECT * INTO NewTable FROM OldTable
Join Fundamentals
By using joins, you can retrieve data from two or more tables based on logical relationships between the
tables. Joins indicate how Microsoft SQL Server should use data from one table to select the rows in
another table.
SQL joins are used to combine rows from two or more tables.
INNER JOIN: Returns all rows when there is at least one match in BOTH tables
OUTER JOIN
o LEFT JOIN: Return all rows from the left table, and the matched rows from the right table
o RIGHT JOIN: Return all rows from the right table, and the matched rows from the left table
o FULL JOIN: Return all rows when there is a match in ONE of the tables
CROSS JOIN: Return Cartesian products result-set from the tables
SELF JOIN
INNER JOIN
This join returns rows when there is at least one match in both the tables.
OUTER JOIN
CROSS JOIN
This join is a Cartesian join that does not necessitate any condition to join. The result-set contains records
that are multiplication of record number from both the tables.
A cross join that does not have a WHERE clause produces the Cartesian product of the tables involved in
the join. The size of a Cartesian product result set is the number of rows in the first table multiplied by the
number of rows in the second table. The following example shows a Transact-SQL cross join.
A self-join is simply a normal SQL join that joins one table to itself. This is accomplished by using table
name aliases to give each instance of the table a separate name. Joining a table to itself can be useful
when you want to compare values in a column to other values in the same column. A join in which
records from a table are combined with other records from the same table when there are matching
values in the joined fields. A self-join can be an inner join or an outer join. A table is joined to itself
based upon a field or combination of fields that have duplicate data in different records. The data-type
of the inter-related columns must be of the same type or needs to cast them in same type.
self-join is a query in which a table is joined (compared) to itself. Self-joins are used to compare
values in a column with other values in the same column in the same table.
SE AdventureWorks;
GO
SELECT DISTINCT pv1.ProductID, pv1.VendorID
FROM Purchasing.ProductVendor pv1
INNER JOIN Purchasing.ProductVendor pv2
ON pv1.ProductID = pv2.ProductID
AND pv1.VendorID = pv2.VendorID
ORDER BY pv1.ProductID
Subquery Fundamentals
A subquery is a query that is nested inside a SELECT, INSERT, UPDATE, or DELETE statement, or inside
another subquery. A subquery can be used anywhere an expression is allowed.
A subquery is also called an inner query or inner select, while the statement containing a subquery is
also called an outer query or outer select.
A subquery nested in the outer SELECT statement has the following components:
Subquery Rules
The select list of a subquery introduced with a comparison operator can include only one
expression or column name (except that EXISTS and IN operate on SELECT * or a list,
respectively).
If the WHERE clause of an outer query includes a column name, it must be join-compatible with
the column in the subquery select list.
The ntext, text, and image data types cannot be used in the select list of subqueries.
Because they must return a single value, subqueries introduced by an unmodified comparison
operator (one not followed by the keyword ANY or ALL) cannot include GROUP BY and HAVING
clauses.
The DISTINCT keyword cannot be used with subqueries that include GROUP BY.
The COMPUTE and INTO clauses cannot be specified.
ORDER BY can only be specified when TOP is also specified.
A view created by using a subquery cannot be updated.
The select list of a subquery introduced with EXISTS, by convention, has an asterisk (*) instead of
a single column name. The rules for a subquery introduced with EXISTS are the same as those for
a standard select list, because a subquery introduced with EXISTS creates an existence test and
returns TRUE or FALSE, instead of data.
Nested Queries
A subquery can itself include one or more subqueries. Any number of subqueries can be nested in a
statement.
Use AdventureWorks2008R2;
GO
SELECT LastName, FirstName
FROM Person.Person
WHERE BusinessEntityID IN
(SELECT BusinessEntityID
FROM HumanResources.Employee
WHERE BusinessEntityID IN
(SELECT BusinessEntityID
FROM Sales.SalesPerson)
)
Correlated Subqueries
Many queries can be evaluated by executing the subquery once and substituting the resulting value or
values into the WHERE clause of the outer query. In queries that include a correlated subquery (also
known as a repeating subquery), the subquery depends on the outer query for its values. This means
that the subquery is executed repeatedly, once for each row that might be selected by the outer query.
This query retrieves one instance of each employee's first and last name for which the bonus in the
SalesPerson table is 5000 and for which the employee identification numbers match in the Employee
and SalesPerson tables.
USE AdventureWorks2008R2;
GO
SELECT DISTINCT c.LastName, c.FirstName, e.BusinessEntityID
FROM Person.Person AS c JOIN HumanResources.Employee AS e
ON e.BusinessEntityID = c.BusinessEntityID
WHERE 5000.00 IN
(SELECT Bonus
FROM Sales.SalesPerson sp
WHERE e.BusinessEntityID = sp.BusinessEntityID) ;
GO
Correlated subqueries can also include table-valued functions in the FROM clause by referencing
columns from a table in the outer query as an argument of the table-valued function. In this case, for
each row of the outer query, the table-valued function is evaluated according to the subquery.
SQL Constraints
SQL constraints are used to specify rules for the data in a table.
If there is any violation between the constraint and the data action, the action is aborted by the
constraint.
Constraints can be specified when the table is created (inside the CREATE TABLE statement) or after the
table is created (inside the ALTER TABLE statement).
The NOT NULL constraint enforces a column to NOT accept NULL values.
The NOT NULL constraint enforces a field to always contain a value. This means that you cannot insert a
new record, or update a record without adding a value to this field.
The following SQL enforces the "P_Id" column and the "LastName" column to not accept NULL values:
Example
CREATE TABLE PersonsNotNull
(
P_Id int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255)
)
The UNIQUE and PRIMARY KEY constraints both provide a guarantee for uniqueness for a column or set
of columns.
Note that you can have many UNIQUE constraints per table, but only one PRIMARY KEY constraint per
table.
To create a UNIQUE constraint on the "P_Id" column when the table is already created, use the
following SQL:
The PRIMARY KEY constraint uniquely identifies each record in a database table.
Each table should have a primary key, and each table can have only ONE primary key.
SQL PRIMARY KEY Constraint on CREATE TABLE
The following SQL creates a PRIMARY KEY on the "P_Id" column when the "Persons" table is created:
To create a PRIMARY KEY constraint on the "P_Id" column when the table is already created, use the
following SQL:
SQL Server
Let's illustrate the foreign key with an example. Look at the following two tables:
The following SQL creates a FOREIGN KEY on the "P_Id" column when the "Orders" table is created:
To create a FOREIGN KEY constraint on the "P_Id" column when the "Orders" table is already created,
use the following SQL:
ALTER TABLE Orders
ADD FOREIGN KEY (P_Id)
REFERENCES Persons(P_Id)
The CHECK constraint is used to limit the value range that can be placed in a column.
If you define a CHECK constraint on a single column it allows only certain values for this column.
If you define a CHECK constraint on a table it can limit the values in certain columns based on values in
other columns in the row.
The following SQL creates a CHECK constraint on the "P_Id" column when the "Persons" table is created.
The CHECK constraint specifies that the column "P_Id" must only include integers greater than 0.
To create a CHECK constraint on the "P_Id" column when the table is already created, use the following
SQL:
To allow naming of a CHECK constraint, and for defining a CHECK constraint on multiple columns, use
the following SQL syntax:
ALTER TABLE Persons
ADD CONSTRAINT chk_Person CHECK (P_Id>0 AND City='Sandnes')
The default value will be added to all new records, if no other value is specified.
The following SQL creates a DEFAULT constraint on the "City" column when the "Persons" table is
created:
To create a DEFAULT constraint on the "City" column when the table is already created, use the
following SQL:
Identity properties:
Auto-increment allows a unique number to be generated when a new record is inserted into a table.
Very often we would like the value of the primary key field to be created automatically every time a new
record is inserted.
Views
A view is a virtual object or table whose result set is derived from a query. It is very similar to a real table
because it contains columns and rows of data. The only time a view is materialized, or stored on disk, is
when it is indexed.Indexed views are discussed later in this chapter.The following are some typical uses
of views:
You can create views using a graphical user interface (GUI) within Microsoft SQL Server Management
Studio (SSMS) or using T-SQL.Before you create any views, you should understand the following:
Views are often used as an abstraction layer for database developers.They are also sometimes used
to secure data in various ways.For example, you may create a view that exposes only specific data. In
turn, instead of granting users permissions to the underlying table, you can grant them permissions to the
view that exposes some of the columns.
As a best practice, you should avoid using SELECT * in views. As table schemas change, so will
the views column listing if SELECT * is used.When writing queries, you should return only those
columns that are required.
You should not use ORDER BY in views because they will not be valid; they are valid only when
used with TOP.In that case, ORDER BY is used to determine which rows are returned.
Specify Computed Columns in a Table
A computed column is a virtual column that is not physically stored in the table, unless the column is
marked PERSISTED. A computed column expression can use data from other columns to calculate a
value for the column to which it belongs. You can specify an expression for a computed column in in SQL
Server 2016 by using SQL Server Management Studio or Transact-SQL.
A computed column cannot be used as a DEFAULT or FOREIGN KEY constraint definition or with a NOT
NULL constraint definition. However, if the computed column value is defined by a deterministic
expression and the data type of the result is allowed in index columns, a computed column can be used
as a key column in an index or as part of any PRIMARY KEY or UNIQUE constraint. For example, if the
table has integer columns a and b, the computed column a + b may be indexed, but computed column a
+ DATEPART(dd, GETDATE()) cannot be indexed, because the value might change in subsequent
invocations.
MERGE is a new feature that provides an efficient way to perform multiple DML operations. In previous
versions of SQL Server, we had to write separate statements to INSERT, UPDATE, or DELETE data
based on certain conditions, but now, using MERGE statement we can include the logic of such data
modifications in one statement that even checks when the data is matched then just update it and when
unmatched then insert it.
One of the most important advantage of MERGE statement is all the data is read and processed only once.
In previous versions three different statement has to be written to process three different activity
(INSERT, UPDATE or DELETE), however using MERGE statement all update activity can be done in
one pass of database table. This is quite an improvement in performance of database query.
Let’s create Student Details and StudentTotalMarks and inserted some records.
Student Details:
USE AdventureWorks
GO
CREATE TABLE StudentDetails
(
StudentID INTEGER PRIMARY KEY,
StudentName VARCHAR(15)
)
GO
INSERT INTO StudentDetails
VALUES(1,'SMITH')
INSERT INTO StudentDetails
VALUES(2,'ALLEN')
INSERT INTO StudentDetails
VALUES(3,'JONES')
INSERT INTO StudentDetails
VALUES(4,'MARTIN')
INSERT INTO StudentDetails
VALUES(5,'JAMES')
GO
StudentTotalMarks:
Now we will write MERGE process for tables created earlier. We will make sure that we will have our
three conditions discussed above are satisfied.
There are two very important points to remember while using MERGE statement.
After the MERGE statement has been executed, we should compare previous resultset and new resultset
to verify if our three conditions are carried out.
MERGE statement is very handy improvement for T-SQL developers who have to update database
tables with complicated logic. MERGE statement also improves the performance of database as it
passes through data only once.
Stored Procedure
In a database management system (DBMS), a stored procedure is a set of Structured Query Language
(SQL) statements with an assigned name that's stored in the database in compiled form so that it can be
shared by a number of programs.
A stored procedure is nothing more than prepared SQL code that you save so you can reuse the code over
and over again
Stronger security
Reuse of code
Easier maintenance
Improved performance
AS
FROM AdventureWorks.Person.Address
AS
SELECT @AddressCount
AS
BEGIN TRY
SELECT 1/0
END TRY
BEGIN CATCH
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_LINE() AS ErrorLine
,ERROR_MESSAGE() AS ErrorMessage;
END CATCH
One of the things you do not want to use as a standard is "sp_". This is a standard naming convention that
is used in the master database. If you do not specify the database where the object is, SQL Server will
first search the master database to see if the object exists there and then it will search the user database.
So avoid using this as a naming convention.
Other Versions
A user-defined function is stored as a database object providing reusable code that can be used in these
ways:
When designing a user-defined function, first determine the type of function that is best suited to your
needs. Will the function:
User-defined functions written in either Transact-SQL or .NET Framework can return both scalar and
table values.
You can create the function once, store it in the database, and call it any number of times in your
program. User-defined functions can be modified independently of the program source code.
Similar to stored procedures, Transact-SQL user-defined functions reduce the compilation cost of
Transact-SQL code by caching the plans and reusing them for repeated executions. This means the
user-defined function does not need to be reparsed and reoptimized with each use resulting in
much faster execution times.
CLR functions offer significant performance advantage over Transact-SQL functions for
computational tasks, string manipulation, and business logic. Transact-SQL functions are better
suited for data-access intensive logic.
An operation that filters data based on some complex constraint that cannot be expressed in a
single scalar expression can be expressed as a function. The function can then invoked in the
WHERE clause to reduce the number or rows sent to the client.
Note
Transact-SQL user-defined functions in queries can only be executed on a single thread (serial execution
plan).
The body defines the action, or logic, the function is to perform. It contains either
Types of Functions
User-defined scalar functions return a single data value of the type defined in the RETURNS clause. For
an inline scalar function, there is no function body; the scalar value is the result of a single statement
CREATE FUNCTION dbo.ufnGetInventoryStock(@ProductID int)
RETURNS int
AS
-- Returns the stock level for the product.
BEGIN
DECLARE @ret int;
SELECT @ret = SUM(p.Quantity)
FROM Production.ProductInventory p
WHERE p.ProductID = @ProductID
AND p.LocationID = '6';
IF (@ret IS NULL)
SET @ret = 0;
RETURN @ret;
END;
User-defined table-valued functions return a table data type. For an inline table-valued function, there is
no function body; the table is the result set of a single SELECT statement.
For a multi statement table-valued function, the function body, defined in a BEGIN...END block,
contains a series of Transact-SQL statements that build and insert rows into the table that will be returned.
The following example creates a table-valued function. The function takes a single input parameter, an
EmployeeID and returns a list of all the employees who report to the specified employee directly or
indirectly. The function is then invoked specifying employee ID 109.
Transact-SQL
USE AdventureWorks2008R2;
GO
IF OBJECT_ID (N'dbo.ufn_FindReports', N'TF') IS NOT NULL
DROP FUNCTION dbo.ufn_FindReports;
GO
CREATE FUNCTION dbo.ufn_FindReports (@InEmpID INTEGER)
RETURNS @retFindReports TABLE
(
EmployeeID int primary key NOT NULL,
FirstName nvarchar(255) NOT NULL,
LastName nvarchar(255) NOT NULL,
JobTitle nvarchar(50) NOT NULL,
RecursionLevel int NOT NULL
)
--Returns a result set that lists all the employees who report to the
--specific employee directly or indirectly.*/
AS
BEGIN
WITH EMP_cte(EmployeeID, OrganizationNode, FirstName, LastName, JobTitle,
RecursionLevel) -- CTE name and columns
AS (
SELECT e.BusinessEntityID, e.OrganizationNode, p.FirstName, p.LastName,
e.JobTitle, 0 -- Get the initial list of Employees for Manager n
FROM HumanResources.Employee e
INNER JOIN Person.Person p
ON p.BusinessEntityID = e.BusinessEntityID
WHERE e.BusinessEntityID = @InEmpID
UNION ALL
SELECT e.BusinessEntityID, e.OrganizationNode, p.FirstName, p.LastName,
e.JobTitle, RecursionLevel + 1 -- Join recursive member to anchor
FROM HumanResources.Employee e
INNER JOIN EMP_cte
ON e.OrganizationNode.GetAncestor(1) = EMP_cte.OrganizationNode
INNER JOIN Person.Person p
ON p.BusinessEntityID = e.BusinessEntityID
)
-- copy the required columns to the result of the function
INSERT @retFindReports
SELECT EmployeeID, FirstName, LastName, JobTitle, RecursionLevel
FROM EMP_cte
RETURN
END;
GO
-- Example invocation
SELECT EmployeeID, FirstName, LastName, JobTitle, RecursionLevel
FROM dbo.ufn_FindReports(1);