Quantcast
Channel: CodeSection,代码区,SQL Server(mssql)数据库 技术分享 - CodeSec
Viewing all articles
Browse latest Browse all 3160

Write more compact SQL Server code using new features

$
0
0
By:Sergey Gigoyan | Last Updated: 2018-11-20 || Related Tips:More > T-SQL Problem

There are some common tasks in SQL Server where past solutions have been a bit long and complicated code. As there are no special functions for these purposes in older versions of SQL Server, but in SQL Server 2016 and 2017 several new functions and features allow Developers to rewrite code in a much more compact way.

Solution

In this tip, we are going to demonstrate some common problems requiring longer, complicated solutions in older versions of SQL Server. Then we will introduce a shorter solution for each task using new features that were released in either SQL Server 2016 and 2017 and will be noted in each solution below.

Create SQL Server Test Environment

Lets create a test environment. This script creates a TestDB database with three tables with data: Student, Course and the StudentCourse table to map their relationships.

USE master
GO
--Database
CREATE DATABASE TestDB
GO
USE TestDB
GO
--Tables
CREATE TABLE Student
(
StudentID INT NOT NULL,
LoginName NVARCHAR(50),
PRIMARY KEY (StudentID)
)
GO
CREATE TABLE Course
(
CourseID INT NOT NULL,
CourseName NVARCHAR(50) UNIQUE,
PRIMARY KEY (CourseID)
)
GO
CREATE TABLE StudentCourse
(
StudentCourseID INT NOT NULL IDENTITY(1,1),
StudentID INT,
CourseID INT,
PRIMARY KEY (StudentCourseID),
CONSTRAINT UC_StudentID_CourseID UNIQUE(StudentID,CourseID),
)
GO
--Filling data
INSERT INTO Student(StudentID, LoginName)
VALUES(1, ' <a href="/cdn-cgi/l/email-protection" data-cfemail="9aeef5f7daeeffe9eeeff4f3ecffe8e9f3eee3b4f9f5f7">[email protected]</a> '),
(2, '<a href="/cdn-cgi/l/email-protection" data-cfemail="c6b5a7ab86b2a3b5b2b3a8afb0a3b4b5afb2bfe8a5a9ab">[email protected]</a> '),
(3, ' <a href="/cdn-cgi/l/email-protection" data-cfemail="583239363d182c3d2b2c2d36312e3d2a2b312c21763b3735">[email protected]</a>'),
(4, '<a href="/cdn-cgi/l/email-protection" data-cfemail="bcddd2d2fcc8d9cfc8c9d2d5cad9cecfd5c8c592dfd3d1">[email protected]</a>')
INSERT INTO Course(CourseID, CourseName)
VALUES(1, 'psychology'),
(2, 'physics'),
(3, 'chemistry'),
(4, 'astrology'),
(5, 'mathematics'),
(6, 'biology'),
(7, 'geography')
INSERT INTO StudentCourse(StudentID, CourseID)
VALUES(1, 1),
(1, 3),
(1, 5),
(2, 5),
(3, 1),
(3, 2),
(3, 3),
(3, 4),
(3, 5),
(3, 6),
(3, 7),
(4, 2),
(4, 4),
(4, 5) Rollup Rows and Create a Comma Separated List

Sometimes we need to represent values from several rows into one column by a using a comma-separated list. So, our first task will be for each student to get his/her login name and enrolled subjects in one row separated by a comma.

To get a list of students and the enrolled courses, we can simply use this code:

USE TestDB
GO
--Getting Students' enrolled courses
SELECT s.LoginName, c.CourseName
FROM StudentCourse sc
INNER JOIN Student s ON sc.StudentID=s.StudentID
INNER JOIN Course c ON c.CourseID=sc.CourseID

This returns a table with two columns showing the mapping between student and course:


Write more compact SQL Server code using new features
Old Way - Rollup rows using STUFF

Our task is to have a table with one row for each student with his/her login and all of his/her courses separated by a comma. In older versions of SQL Server, we can use STUFF with FOR XML PATH to solve the problem as follows:

USE TestDB
GO
--USING STUFF and FOR XML PATH in older versions of SQL Server
SELECT
LoginName,
STUFF(( SELECT ',' + c.CourseName AS [text()]
FROM StudentCourse sc
INNER JOIN Course c ON c.CourseID=sc.CourseID
WHERE sc.StudentID = st.StudentID
FOR XML PATH('')
), 1, 1, '' ) AS StudentCourses
FROM Student st

We will receive the desired result:


Write more compact SQL Server code using new features
New Way - Rollup rows using STRING_AGG

SQL Server 2017 introduces a new string function STRING_AGG. It is an aggregate function that concatenates the values of rows (expression) into a single string separated by the given separator. As you can guess, it is an ideal function for solving our task. We can rewrite the code in SQL Server 2017 in the following way:

USE TestDB
GO
--SQL Server 2017 and later
SELECT s.LoginName, STRING_AGG(c.CourseName, ',') AS StudentCourses
FROM StudentCourse sc
INNER JOIN Student s ON sc.StudentID=s.StudentID
INNER JOIN Course c ON c.CourseID=sc.CourseID
GROUP BY s.LoginName

So, we have a simpler and more compact code to get the same result:


Write more compact SQL Server code using new features
Replacing Leading and Trailing Spaces in a String

In our above example, you may have noticed that some of login names contain spaces. So our second task is to get the same result as in the previous task, but without spaces in the LoginName.

Old Way - Use LTRIM and RTRIM to remove unwanted leading and trailing spaces

In older versions of SQL Server, we use LTRIM and RTRIM functions to replace all spaces in a string:

USE TestDB
GO
-- Using LTRIM with RTRIM in older versions of SQL Server (note this code will not work in older versions because STRING_AGG is used)
SELECT RTRIM(LTRIM(s.LoginName)) AS LoginName, STRING_AGG(c.CourseName, ',') AS StudentCourses
FROM StudentCourse sc
INNER JOIN Student s ON sc.StudentID=s.StudentID
INNER JOIN Course c ON c.CourseID=sc.CourseID
GROUP BY s.LoginName
Write more compact SQL Server code using new features
New Way - Use TRIM to remove unwanted leading and trailing spaces

SSQL Server 2017 introduced the TRIM function, which removes blanks (or other specified characters) from both the beginning and end of the given string. So, in SQL Server 2017 the code above can be rewritten by using just the TRIM, instead of two separate functions:

USE TestDB
GO
--SQL Server 2017 and later
SELECT TRIM(s.LoginName) AS LoginName, STRING_AGG(c.CourseName, ',') AS StudentCourses
FROM StudentCourse sc
INNER JOIN Student s ON sc.StudentID=s.StudentID
INNER JOIN Course c ON c.CourseID=sc.CourseID
GROUP BY s.LoginName Replacing Values in a String

Now, let’s assume that special characters in a string should be replaced by others. Let's say we have a list of subjects separated by the following symbols: , / - _ | . An example string is: 'psychology/physics,chemistry-astrology_mathematics|biology,geography' . It is required to use a comma as the only separator. In other words, any of these other symbols should be replaced with a comma.

Old Way - Replace values in a string using the REPLACE function

Before SQL Server 2017 we can do this by nesting REPLACE functions several times for each of the symbols. Since we are replacing four different values, we need to use the REPLACE function four times as follows:

USE TestDB
GO
--In older versions of SQL Server
DECLARE @str NVARCHAR(MAX)='psychology/physics,chemistry-astrology_mathematics|biology,geography'
SET @str=REPLACE(REPLACE(REPLACE(REPLACE(@str,'|',','),'_',','),'-',','),'/',',')
SELECT @str AS 'Subjects'

We will have the list of these subjects separated only by comma:


Viewing all articles
Browse latest Browse all 3160

Trending Articles