concatenation in sql query is the operation of combining two or more string values or columns into a single string, performed using vendor-specific functions like CONCAT() or operators || and +.
-- Concatenate first and last names using CONCAT (SQL Server 2012+)
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM employees;
Dialect and NULL handling overview
String concatenation merges text from separate columns—combining first and last names, formatting addresses, or generating dynamic labels. In SQL Server, CONCAT() ignores NULL arguments, while the + operator propagates NULL. PostgreSQL, Oracle, and MySQL support the || operator; SQL Server 2025 added || for cross‑vendor compatibility. Choose the method based on NULL handling needs, implicit type conversion, and output length limits.
Tested on SQL Server 2022 (16.x) with SSMS 19.0; also verified on PostgreSQL 15 and MySQL 8.0.
SQL concatenation Syntax Reference
Using CONCAT() (SQL Server 2012+, Azure SQL Database)
-- Basic syntax: CONCAT ( argument1, argument2 [, argumentN ] )
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM employees;
Using CONCAT_WS() (SQL Server 2017+, Azure SQL DB)
-- Adds a separator; ignores NULL values
SELECT CONCAT_WS(', ', last_name, first_name) AS full_name FROM employees;
Using + operator (all SQL Server versions)
-- NULL propagates: if either operand is NULL, result is NULL
SELECT first_name + ' ' + last_name AS full_name FROM employees;
Using || operator (PostgreSQL, Oracle, MySQL, SQL Server 2025+)
-- Standard SQL; NULL propagates in most implementations
SELECT first_name || ' ' || last_name AS full_name FROM employees;
SQL concatenation Rapid Reference Cheat Sheet
| Action | SQL Syntax | Dialect | NULL Handling | Max Output Length |
|---|---|---|---|---|
| Basic concatenation | CONCAT(a, b) |
SQL Server, Azure SQL | NULLs → empty string | 8,000 chars (varchar), unless LOB type |
| With separator | CONCAT_WS(sep, a, b) |
SQL Server 2017+, Azure SQL | NULLs ignored; separator not added after NULL | 8,000 chars |
| Using + operator | a + b |
SQL Server | NULL propagates → result NULL | 8,000 chars |
| Using || operator | a || b |
PostgreSQL, Oracle, MySQL, SQL Server 2025+ | NULL propagates (varies by DB) | Unlimited in PG/MySQL; 8k in SQL Server |
| Numeric literal concatenation | CONCAT(emp_id, ': ', salary) |
All (implicit conversion) | Numeric implicitly converted to string | Depends on function |
Advanced Implementation & Parameters
Return types and length limits
CONCAT() returns a string whose type is determined by the input arguments. If any argument has a supported large object (LOB) type (varchar(max), nvarchar(max), varbinary(max)), the result type becomes varchar(max) / nvarchar(max). Otherwise the output is truncated to 8,000 characters. + operator exhibits the same truncation behavior. Use explicit CAST or CONVERT to control type:
SELECT CONCAT(CAST(product_id AS VARCHAR(10)), ' - ', product_name) AS product_label FROM products;
Implicit conversion
CONCAT() automatically converts all arguments to strings before concatenation. For numeric, date, and binary types, the conversion follows the rules of CAST (e.g., GETDATE() converts to the default datetime format). The + operator does not perform implicit conversion when both operands are not strings—this raises an error:
-- Error: Operand type clash: int is incompatible with varchar
SELECT 100 + ' has salary ';
Use CONCAT() or explicit CAST for mixed types.
Performance considerations
CONCAT() is generally faster than repeated + concatenation because it evaluates all arguments in a single pass. Avoid overuse in WHERE clauses; concatenating columns prevents index usage. For example:
-- Inefficient: forces full scan
WHERE CONCAT(first_name, ' ', last_name) = 'John Doe';
-- Efficient: use equality on separate columns
WHERE first_name = 'John' AND last_name = 'Doe';
Error Resolution & Troubleshooting
| Error / Issue | Cause | Remediation |
|---|---|---|
NULL result with + |
One operand is NULL |
Replace + with CONCAT() or wrap with ISNULL(): ISNULL(first_name, '') + ' ' + ISNULL(last_name, '') |
| Truncation to 8,000 characters | No LOB input arguments | Cast at least one argument to VARCHAR(MAX): CONCAT(CAST(col AS VARCHAR(MAX)), col2) |
Operand type clash with + |
Using + on numeric/date with string without implicit conversion |
Use CONCAT() or explicit CAST: CAST(integer_col AS VARCHAR) + string_col |
CONCAT requires at least 2 arguments |
Syntax error with single argument | Provide minimum two arguments; use CONCAT_WS for a single‑argument scenario with separator |
|| not recognized in SQL Server <2025 |
Older SQL Server version | Use CONCAT() or + operator; or upgrade to SQL Server 2025 |
Production‑Grade Implementation
Best practices for performance and maintainability
- Prefer
CONCAT()over+for null‑safe concatenation. This eliminatesISNULL()wrappers and reduces code verbosity. - Use
CONCAT_WS()for comma‑separated lists to avoid manually adding delimiters. - Avoid concatenation in
WHEREclauses. Instead use separate column conditions or computed columns with indexes. - Explicitly cast LOB inputs when combining
VARCHAR(MAX)with smaller types to avoid implicit conversion overhead. - Monitor for tempdb spillovers when concatenating many rows inside
STRING_AGG()orSELECT ... FOR XML PATHas an alternative to group concatenation. - Test with actual data volumes – concatenating in SELECT statements that return millions of rows can increase memory grants and CPU.
Security & least privilege
No special permissions are required for CONCAT(); standard SELECT privileges on the underlying columns suffice. Avoid dynamic SQL to build concatenated strings that might be exposed to injection. If you must concatenate user‑supplied values, use QUOTENAME() or parameterized queries.
Frequently Asked Questions
What is the difference between CONCAT() and the || operator in SQL?
Answer: CONCAT() treats NULLs as empty strings, while || returns NULL if any operand is NULL. Use CONCAT() for cross‑DB portability (MySQL, PostgreSQL, SQL Server 2012+). The || operator is ANSI SQL but behaves differently: in MySQL it conflicts with logical OR. Example:
-- CONCAT handles NULLs
SELECT CONCAT('a', NULL, 'b'); -- Returns 'ab'
-- || in PostgreSQL returns NULL
SELECT 'a' || NULL || 'b'; -- Returns NULL
When should I use CONCAT_WS() for string concatenation?
Answer: Use CONCAT_WS() when you need to concatenate multiple values with a consistent separator and skip NULLs automatically. Available in MySQL, MariaDB, and SQLite. Ideal for building CSV or delimited output without manual NULL checks. Example:
-- Combine first, middle, last with spaces
SELECT CONCAT_WS(' ', first_name, middle_name, last_name)
FROM employees;
-- Skips middle_name if NULL
How do I fix error “Implicit conversion of varchar to int” when concatenating columns?
Answer: Explicitly convert non‑string columns using CAST() or CONVERT() before concatenation, or use CONCAT() which auto‑converts. In SQL Server, mixing string and numeric columns with + triggers this error. Fix:
-- Wrong
SELECT 'ID: ' + employee_id FROM employees; -- Error
-- Correct
SELECT 'ID: ' + CAST(employee_id AS VARCHAR) FROM employees;
-- Or use CONCAT() which auto-converts:
SELECT CONCAT('ID: ', employee_id) FROM employees;
Does the CONCAT() function work on all major SQL databases?
Answer: No. For cross‑DB scripting, prefer the ANSI SQL || operator where supported, or use platform‑specific functions. Example for SQLite:
-- SQLite uses || instead of CONCAT()
SELECT 'Name: ' || first_name || ' ' || last_name FROM users;
What is the fastest way to concatenate many columns with a delimiter in MySQL?
Answer: Use CONCAT_WS() for readability and performance; avoid nested CONCAT() or repetitive + operators. CONCAT_WS is optimized in MySQL and avoids temporary row expansion. Example for large dataset:
-- Fastest: one function call, skips NULLs
SELECT CONCAT_WS(',', col1, col2, col3, col4, col5)
FROM huge_table;
-- Avoid multiple CONCAT calls:
-- CONCAT(col1, ',', col2, ',', ...) is slower.

Command Line Expert & Software Engineer
Welcome! I’m Thomas Heinrich, a software engineer and system administrator with a deep passion for the Command Line Interface (CLI). With years of experience navigating the terminal, building backend architectures, and automating server deployments, I created this space to share practical, real-world terminal knowledge.
Whether you are a beginner taking your first steps in a Linux environment or a seasoned DevOps engineer looking to optimize your deployment scripts, you will find actionable solutions here. My goal is to help you ditch the mouse, speed up your workflow, and harness the full power of the command line.