![]() |
|

SQL Monitor offers straightforward server monitoring through a web-based UI, to help you prioritize your workload:
Start monitoring your servers today with a free trial.
|
|
By: Sherlee Dizon | Read Comments (6) | Related Tips: More > Functions - System |
In this article I would like to share some tips on using concatenation efficiently for application development. Here I would like to point out some things that we must consider and look at when concatenating values or fields in our queries or stored procedures. Check out this tip to learn more.
String concatenation is appending one string to the end of another string. The SQL language allows us to concatenate strings, but the syntax varies according to which database system we are using. Concatenation can be used to join strings from different sources including column values, literal strings, output from user defined functions, scalar sub queries, etc. Let's jump into how to concatenate strings.
From SQL Server 2008 R2 version and below the + (plus sign) is an operator used in a string expression that concatenates two or more character or binary strings, columns, or a combination of strings and column names into one expression or into another column.
From SQL Server 2008, 2008 R2 and 2012 versions += (add equals sign) is another string concatenation operator, which can be used to concatenate two strings and sets the string to the result of the operation. This operator cannot be used without a variable otherwise the query execution fails.
Now SQL Server 2012 brings us CONCAT() a new function for concatenation. It returns a string that is the result of concatenating two or more string values. The new function implicitly converts all arguments to string types and then concatenates the inputs. It requires a minimum of two input values or the concatenation fails.
One of the principles of relational database design is that the fields of the data tables should reflect a single characteristic of the table's subject, which means that they should not contain concatenated strings. For example, to display the physical address of a certain employee, the data might include building subunit number, building name, street name, city name, province name, postal code, and country name, e.g., "Unit 2307 ABC Tower Salcedo St. Makati City, 1402, Philippines", which combines 7 fields.
However, the employees data table should not use one field to store that concatenated string; rather, the concatenation of the 7 fields should happen upon running the report or the application. The reason for such principles is that without them, the entry and updating of large volumes of data becomes error-prone and labor-intensive. Separately entering the city, ZIP code, and nation allows data-entry validation (such as detecting an invalid zip code). Then those separate items can be used for sorting or indexing the records, such as all with "Makati" as the city name.
Concatenation can deliver result in a more readable format while maintaining data in separate columns for greater flexibility. Below are some uses of string concatenation in SQL Server:
1. Know where the query result set will be used.
2. Know who will use or who will need the query result set.
3. Know how large the strings to be concatenated are.
4. Know how big the data you need to query and to display is.
5. Know if the data you need can be a null value.
Concatenation varies by database type and version. Check out these examples to see code in action.
Microsoft Access uses the "+" plus operator to perform concatenation. The example below appends the value in the FirstName column with a blank space i.e. ' ' and then appends the value from the LastName column. The resulting string is given an Alias of FullName so we can easily identify it in our result set.
SELECT FirstName + ' ' + LastName As FullName FROM Employees
Oracle uses the CONCAT(string1, string2) function or the || operator. The Oracle CONCAT function can only take two strings so the above example would not be possible as there are three strings to be joined (FirstName, ' ' and LastName). To achieve this in Oracle we would need to use the || operator which is equivalent to the + string concatenation operator in SQL Server and Access.
SELECT FirstName || ' ' || LastName As FullName FROM Employees
MySQL uses the CONCAT(string1, string2, string3...) function. The above example would appear as follows in MySQL.
SELECT CONCAT(FirstName, ' ', LastName) As FullName FROM Employees
In this example I will concatenate 2 columns which are both using string characters with data type of nvarchar into one column.
USE AdventureWorks; SELECT GroupName + ' - ' + Name as AdventureWorksDept FROM [HumanResources].[Department] ORDER BY GroupName
Here's the result set.
In concatenating numbers we need to convert them into string. We can use CAST() or CONVERT() function to do that. In this example, I will calculate the sum of all vacation and sick leave hours per production department then concatenate a string to the total hours.
USE AdventureWorks; SELECT [Title], 'Total Vacation Hours : ' + CONVERT(varchar(5),SUM([VacationHours])) AS VacationHours, 'Total Sick Leave Hours : ' + CONVERT(varchar(5),SUM([SickLeaveHours])) AS SickLeaveHour FROM [AdventureWorks].[HumanResources].[Employee] WHERE TITLE LIKE 'Production%' GROUP BY [Title] ORDER BY SUM([VacationHours]),SUM([SickLeaveHours])
Here's the result set.
Just like in concatenating numbers we need to convert dates into string as well. We can use CAST() or CONVERT() function too.
USE AdventureWorks; SELECT empDeptHist.[StartDate],HRDept.[Name] as DeptName, CONVERT(varchar(5),COUNT(empDeptHist.[EmployeeID])) AS EmpCount, CONVERT(varchar(5),COUNT(empDeptHist.[EmployeeID])) + ' ' + CONVERT(varchar(12), empDeptHist.[StartDate], 101) as ConcatenatedNumberDate FROM [HumanResources].[EmployeeDepartmentHistory] empDeptHist LEFT OUTER JOIN [HumanResources].[Department] HRDept ON empDeptHist.[DepartmentID] = HRDept.[DepartmentID] WHERE HRDept.[Name] = 'Sales' GROUP BY empDeptHist.[StartDate],HRDept.[Name]
Here's the result set.
Here's the easiest way to concatenate string and a date.
SELECT 'Today is :' + SPACE(5) + CONVERT(varchar(12), GETDATE(), 101) AS CurrentDate
Here's the result set.
Now let's try to concatenate different data types into one column.
USE AdventureWorks; SELECT empDeptHist.[StartDate],HRDept.[Name] as DeptName, CONVERT(varchar(5),COUNT(empDeptHist.[EmployeeID])) AS EmpCount, HRDept.[Name] + ' with ' + CONVERT(varchar(5),COUNT(empDeptHist.[EmployeeID])) + ' employee hired for ' + CONVERT(varchar(12), empDeptHist.[StartDate], 101) as ConcatenatedValues FROM [HumanResources].[EmployeeDepartmentHistory] empDeptHist LEFT OUTER JOIN [HumanResources].[Department] HRDept ON empDeptHist.[DepartmentID] = HRDept.[DepartmentID] WHERE HRDept.[Name] like 'Shipping%' GROUP BY empDeptHist.[StartDate],HRDept.[Name]
Here's the result set.
In this example I will show how to handle the NULL values IMPLICITY and EXPLICITLY. We can handle null values explicitly by using ISNULL() or the COALESCE() function.
USE AdventureWorks; SELECT TOP 10 [Title],[FirstName],[MiddleName],[LastName],[Suffix] ,[Title]+' '+[FirstName]+' '+[MiddleName]+' '+[LastName]+' '+[Suffix] as HandlingNULLImplicitly ,ISNULL([Title],'') + ' ' + ISNULL([FirstName],'') + ' ' + ISNULL([MiddleName],'') + ' ' + ISNULL([LastName],'') + ' ' + ISNULL([Suffix],'') as HandlingNULLexplicitly ,COALESCE([Title],'') + ' ' + COALESCE([FirstName],'') + ' ' + COALESCE([MiddleName],'') + ' ' + COALESCE([LastName],'') + ' ' + COALESCE([Suffix],'') as UsingCoalesce FROM [AdventureWorks].[Person].[Contact] WHERE [Title]='Mr.'
Here's the result set.
In this example I will try to concatenate rowguid which has a unique identifier data type.
USE AdventureWorks; SELECT TOP 10 [FirstName], [LastName], [rowguid], len([rowguid]) as char_count ,CAST([rowguid] as varchar(36)) + ' ==> ' + [LastName] + ', '+ [FirstName] as ConcatenatedValue FROM [AdventureWorks].[Person].[Contact]
Here's the result set.
In this example I will show how to concatenate the list of department of a specific group separated by a comma into one column only.
USE AdventureWorks; SELECT [DepartmentID],[Name],[GroupName] FROM [AdventureWorks].[HumanResources].[Department] WHERE [GroupName]= 'Executive General and Administration' DECLARE @GroupDept VARCHAR(8000) SELECT @GroupDept = COALESCE(@GroupDept + ', ', '') + Name FROM [AdventureWorks].[HumanResources].[Department] WHERE [GroupName]= 'Executive General and Administration' SELECT 'Executive General and Administration Group Departments are ' + @GroupDept + '.' AS GroupDeptList
Here's the result set. To check if the concatenated values are correct I've included the list of department name for the selected group name.
In this example I will summarize data into groups or list of values in two ways by using correlated sub query or by using CROSS APPLY.
USE AdventureWorks;
-- Using correlated subquery
SELECT G.GroupName,
STUFF( (SELECT ', ' + DN.Name
FROM HumanResources.Department AS DN
WHERE DN.GroupName = G.GroupName
ORDER BY G.GroupName
FOR XML PATH('') ), 1, 1, '') AS dept_list
FROM HumanResources.Department AS G
GROUP BY GroupName
-- Using CROSS APPLY
SELECT G.GroupName,
STUFF(P.dept_list, 1, 1, '') AS dept_list
FROM HumanResources.Department AS G
CROSS APPLY (SELECT ', ' + DN.Name
FROM HumanResources.Department AS DN
WHERE DN.GroupName = G.GroupName
ORDER BY G.GroupName
FOR XML PATH('') ) AS P (dept_list)
GROUP BY GroupName,P.dept_list
Here's the result set. This approach can be use in some reporting purposes to summarize normalized tables into groups or list of values. There are also some reporting and client side tools that support this directly. This method is often called the XML black box method. The PATH clause is used with the input string that indicates the name of the wrapper element that will be created. When the PATH clause is used with an empty string it is used as an input it results in skipping the wrapper element generation.
Here's the query to validate the data is correct.
USE AdventureWorks; SELECT GroupName, Name FROM HumanResources.Department ORDER BY GroupName
In this example I will concatenate 2 columns which are both nvarchar data types into one column, but this time by using the new CONCAT function in SQL Server 2012.
USE AdventureWorks; SELECT CONCAT([GroupName] , ' - ' , [Name]) as AdventureWorksDept2012 FROM [HumanResources].[Department] ORDER BY [GroupName]
Here's the result set.
Keep in mind even though we are currently using Microsoft SQL Server 2012 we can still use the previous syntax which is + (plus sign). It will produce the same results. There's nothing to worry about if you have to use or migrate your previous stored procedure created with the previous syntax.
USE AdventureWorks;
SELECT [Title], CONCAT('Total Vacation Hours : ', SUM([VacationHours])) AS VacationHours
,CONCAT('Total Sick Leave Hours : ', SUM([SickLeaveHours])) AS SickLeaveHour
FROM [AdventureWorks].[HumanResources].[Employee]
WHERE TITLE LIKE 'Production%'
GROUP BY [Title]
ORDER BY SUM([VacationHours]),SUM([SickLeaveHours])
Here's the result set.
Here's how easy it is to concatenate numbers and dates in SQL Server 2012. For this example I try to concatenate the total count of employee hired per department based on their start date.
USE AdventureWorks; SELECT empDeptHist.[StartDate],HRDept.[Name] as DeptName, CONVERT(varchar(5),COUNT(empDeptHist.[EmployeeID])) AS EmpCount, CONCAT(COUNT(empDeptHist.[EmployeeID]) , ' ', CONVERT(varchar(12), empDeptHist.[StartDate], 101)) as ConcatenatedNumberDate FROM [HumanResources].[EmployeeDepartmentHistory] empDeptHist LEFT OUTER JOIN [HumanResources].[Department] HRDept ON empDeptHist.[DepartmentID] = HRDept.[DepartmentID] WHERE HRDept.[Name] = 'Sales' GROUP BY empDeptHist.[StartDate],HRDept.[Name]
Here's the result set.
For this example I will concatenate a string to the current date and display it in one column.
SELECT CONCAT('Today is :', SPACE(5), CONVERT(varchar(12), GETDATE(), 101)) AS CurrentDate
Here's the result set.
USE AdventureWorks; SELECT empDeptHist.[StartDate],HRDept.[Name] as DeptName, CONVERT(varchar(5),COUNT(empDeptHist.[EmployeeID])) AS EmpCount, CONCAT(HRDept.[Name] , ' with ', COUNT(empDeptHist.[EmployeeID]) , ' employee hired for ', CONVERT(varchar(12), empDeptHist.[StartDate], 101)) as ConcatenatedValues FROM [HumanResources].[EmployeeDepartmentHistory] empDeptHist LEFT OUTER JOIN [HumanResources].[Department] HRDept ON empDeptHist.[DepartmentID] = HRDept.[DepartmentID] WHERE HRDept.[Name] like 'Shipping%' GROUP BY empDeptHist.[StartDate],HRDept.[Name]
Here's the result set.
In this example I will show that the "+" plus sign still works in 2012 and how it differs to the new CONCAT() function.
USE AdventureWorks; SELECT TOP 10 [Title],[FirstName],[MiddleName],[LastName],[Suffix] ,[Title]+' '+[FirstName]+' '+[MiddleName]+' '+[LastName]+' '+[Suffix] as HandlingNULLImplicitly ,ISNULL([Title],'') + ' ' + ISNULL([FirstName],'') + ' ' + ISNULL([MiddleName],'') + ' ' + ISNULL([LastName],'') + ' ' + ISNULL([Suffix],'') as HandlingNULLexplicitly ,COALESCE([Title],'') + ' ' + COALESCE([FirstName],'') + ' ' + COALESCE([MiddleName],'') + ' ' + COALESCE([LastName],'') + ' ' + COALESCE([Suffix],'') as UsingCoalesce ,CONCAT([Title] , ' ' + [FirstName] , ' ' , [MiddleName] , ' ' , [LastName] , ' ' , [Suffix]) as UsingCONCAT FROM [AdventureWorks].[Person].[Contact] WHERE [Title]='Mr.'
Here's the result set. From the result set below notice that CONCAT function implicitly coverts all arguments to string types and then concatenate the inputs. The CONCAT function only requires a minimum of two input values else the concatenation fails.
In this example I will try to concatenate rowguid which has a unique identifier data type using the new function and the previous syntax for concatenation to be able to see their difference.
USE AdventureWorks; SELECT TOP 10 [FirstName], [LastName], [rowguid], len([rowguid]) as char_count ,CAST([rowguid] as varchar(36)) + ' ==> ' + [LastName] + ', '+ [FirstName] as ConcatenatedValue ,CONCAT([rowguid] , ' ==> ' , [LastName] , ', '+ [FirstName]) as UsingCONCAT FROM [AdventureWorks].[Person].[Contact]
Here's the result set.
In this example I will show how to concatenate the list of department of a specific group separated by a comma into one column only.
USE AdventureWorks;
SELECT [DepartmentID],[Name],[GroupName]
FROM [AdventureWorks].[HumanResources].[Department]
WHERE [GroupName]= 'Executive General and Administration'
DECLARE @GroupDept VARCHAR(8000)
SELECT @GroupDept = CONCAT(@GroupDept,', ', Name )
FROM [AdventureWorks].[HumanResources].[Department]
WHERE [GroupName]= 'Executive General and Administration'
SELECT CONCAT('Executive General and Administration Group departments are ',
@GroupDept , '.') AS GroupDeptList
Here's the result set. To check if the concatenated values are correct I've included the list of department names for the selected group name.
In this example I will summarize data into groups or list of values in two ways by using correlated sub query or by using CROSS APPLY.
USE AdventureWorks;
-- Using correlated subquery
SELECT G.GroupName,
STUFF( (SELECT CONCAT(', ' , DN.Name)
FROM HumanResources.Department AS DN
WHERE DN.GroupName = G.GroupName
ORDER BY G.GroupName
FOR XML PATH('') ), 1, 1, '') AS dept_list
FROM HumanResources.Department AS G
GROUP BY GroupName
-- Using CROSS APPLY
SELECT G.GroupName,
STUFF(P.dept_list, 1, 1, '') AS dept_list_UsingCROSS_APPLY
FROM HumanResources.Department AS G
CROSS APPLY (SELECT CONCAT(', ' , DN.Name)
FROM HumanResources.Department AS DN
WHERE DN.GroupName = G.GroupName
ORDER BY G.GroupName
FOR XML PATH('') ) AS P (dept_list)
GROUP BY GroupName,P.dept_list
Here's the result set. This approach can be use in some reporting purposes to summarize normalized tables into groups or list of values. There are also some reporting and client side tools that support this directly. This method is often called the XML black box method. The PATH clause is used with input string that indicates the name of the wrapper element that will be created. When PATH clause with an empty string is used as an input it results in skipping the wrapper element generation.
Here's the query to check the data.
USE AdventureWorks; SELECT GroupName, Name FROM HumanResources.Department ORDER BY GroupName
It is not enough that we know how to concatenate strings or values. We must also know where and when to use it. Also always take into consideration the end-user who will use the output. Various programming considerations are to be carefully considered to choose one method over another depending on the situations. Always check and remember the limitations of each approach. One of the most logical choices would be the availability of a built-in operator with optional configurable parameters that can perform the concatenation of the values depending on the data type.
| Thursday, October 18, 2012 - 5:35:29 PM - TimothyAWiseman | Read The Tip |
|
Thank you for the article, I particularly liked the comparisons with other RDBMS. I would respectfully add that it often makes sense to let the presentation or application layers handle concatenation, but as you say it all depends on how the system is meant to work together. Also, Jeff Moden has an excellent somewhat related article on the effeciency of certain types of string concatenation in SQL Server. |
|
| Thursday, October 18, 2012 - 7:45:03 PM - Suman | Read The Tip |
|
I like your analogy on Concatenation. Please come up with more similar articles:) |
|
| Friday, October 19, 2012 - 12:11:32 AM - patty boy ricarte | Read The Tip |
|
Thank you for the article, I particularly liked the comparisons with other RDBMS. I would respectfully add that it often makes sense to let the presentation or application layers handle concatenation, but as you say it all depends on how the system is meant to work together. I like your analogy on Concatenation. Please come up with more similar articles:) Ilike also the explanation on sqlconcat.
more article pls. |
|
| Saturday, October 20, 2012 - 2:20:06 AM - Sherlee | Read The Tip |
|
Thanks TimothyAWiseman. Thank you Suman sure I will try whenever I got the time. |
|
| Tuesday, November 06, 2012 - 11:48:19 AM - Megan Brooks | Read The Tip |
|
You can pre-concatenate a string built from fields, such as an address line, by adding it as a calculated field in the table containing the individual fields. You then have the option of saving the resulting string in the table to avoid the overhead of re-creating it each time (SQL Server recalculates when any of the input fields changes). This is especially useful if the concatenation process is expensive, such as when user-defined functions are invoked to clean up 'messy' source fields. Doing the work in the application would be better, but is not always an option. |
|
| Wednesday, February 20, 2013 - 5:43:11 AM - Sherlee | Read The Tip |
|
Thanks Megan Brooks. I haven't try that approach yet but I will when I need it.
|
|
|
privacy | disclaimer | copyright | advertise | about authors | contribute | feedback | giveaways | user groups Some names and products listed are the registered trademarks of their respective owners. Edgewood Solutions LLC | MSSharePointTips.com | MSSQLTips.com |