Save Big on Cyber Monday! Up to 40% Off
ends in   {{days}}
Days
{{timeFormat.hours}}
:
{{timeFormat.minutes}}
:
{{timeFormat.seconds}}

How to Use the QUOTENAME() Function in SQL Server

SQL QUOTENAME keeps your system stable as it evolves: when identifiers change, naming conventions drift, and reserved words slip into object names. It gives you control over whether those names are generated from code, introduced by users, or shaped by inconsistent schema design. But like any precision tool, its value depends on how and when you apply it.

This guide explores the practical use of SQL QUOTENAME in today's SQL Server IDEs. From syntax and delimiters to common pitfalls and function comparisons, you'll understand how to use it confidently in dynamic, production-grade code.

SQL Server QUOTENAME() syntax and parameters

The QUOTENAME() function in SQL Server safely wraps identifiers, such as table names, column names, or schemas, with delimiters. This ensures those identifiers are correctly parsed, even if they include spaces, special characters, or reserved keywords. It's a fundamental tool for building dynamic SQL and writing scripts that handle unpredictable naming without risking syntax errors or injection vulnerabilities.

When you need to programmatically reference object names in SQL Server, QUOTENAME() is the function that ensures you're doing it safely and correctly.

Basic syntax

The function accepts a string and, optionally, a single character to define the quoting style. If no second argument is provided, it defaults to square brackets.

QUOTENAME(string, [quote_character])
  • string - the identifier to enclose. Must be 128 characters or fewer.
  • quote_character (optional) - a single character used to apply symmetric delimiters.

An example of using the default brackets

SELECT QUOTENAME('select');
-- Output: [select]

Even though select is a reserved keyword, it is treated as a valid identifier when quoted.

Optional quote characters

By default, QUOTENAME() uses square brackets [], but SQL Server allows several other symmetric characters. When you specify one, the function automatically adds both the opening and closing delimiter.

Supported characters are shown in the table below.

Input character Output format
[ or ] [identifier]
" "identifier"
' 'identifier'
{ or } {identifier}
( or ) (identifier)
< or > <identifier>

Examples

SELECT QUOTENAME('product name', '"');
-- "product name"

SELECT QUOTENAME('sales-total', '''');
-- 'sales-total'

Only one character is needed; the function applies it to both sides automatically.

Constraints to keep in mind

When using QUOTENAME() in SQL Server, keep the following limitations in mind to avoid unexpected NULL results or errors:

Input length must not exceed 128 characters

If the input string is longer than 128 characters, QUOTENAME() will return NULL. This limit is fixed and enforced internally.

SELECT QUOTENAME(REPLICATE('x', 129));
-- Returns NULL

Only specific delimiters are allowed

The second argument (custom quote character)must be one of the supported delimiters: [, ", ', (, {, <, or `. Using any other character will result in NULL.

SELECT QUOTENAME('value', '!');
-- Returns NULL

NULL input returns NULL

If the first argument is NULL, the function will return NULL regardless of the specified delimiter.

SELECT QUOTENAME(NULL);
-- NULL
SELECT QUOTENAME(NULL, '"');
-- NULL

These rules are built into SQL Server and consistently apply across versions. Understanding them helps prevent silent failures and ensures your dynamic SQL remains stable.

Common use cases of QUOTENAME()

The QUOTENAME() function becomes essential when dealing with identifiers that can break SQL syntax or introduce security risks. Whether working with reserved words, non-standard naming conventions, or dynamic SQL, this function allows your scripts to handle those cases safely and consistently.

Using QUOTENAME() with reserved words

SQL Server has many reserved keywords, such as select, order, and group, that can't be used directly as object names without causing errors. QUOTENAME() allows you to use these words as identifiers by wrapping them in square brackets or another supported delimiter.

SELECT QUOTENAME('select');
-- Output: [select]

This lets you reference a column or alias named select without conflicting with SQL syntax.

Wrapping identifiers with spaces or special characters

Identifiers with spaces, hyphens, or other special characters must also be delimited to avoid syntax issues. This is especially common in legacy databases, user-defined aliases, and auto-generated schema objects.

SELECT QUOTENAME('Total Sales');
-- [Total Sales]

SELECT QUOTENAME('customer-name');
-- [customer-name]

SELECT QUOTENAME('order#2025', '"'); 
-- "order#2025"

Using QUOTENAME() ensures these names are correctly interpreted as literals, not broken apart or misread by the parser.

Dynamic SQL scenarios

When constructing dynamic SQL, QUOTENAME() is critical for both correctness and security. It prevents syntax errors when injecting object names into query strings and acts as a defense against SQL injection by rejecting unsafe inputs, such as strings with unmatched delimiters.

Unsafe example (do not use)

DECLARE @table NVARCHAR(100) = 'orders';
DECLARE @sql NVARCHAR(MAX) = 'SELECT * FROM ' + @table;
EXEC(@sql);

Safe version using QUOTENAME() and sp_executesql

DECLARE @table NVARCHAR(100) = 'orders';
DECLARE @sql NVARCHAR(MAX) = 'SELECT * FROM ' + QUOTENAME(@table);
EXEC sp_executesql @sql;

In this case, even if the @table value were user-supplied, QUOTENAME() would wrap it safely and reject invalid input (e.g., strings with closing brackets), reducing the risk of injection or malformed queries.

Dynamic SQL without QUOTENAME() is a gamble. With it, your scripts gain a critical layer of protection and stability.

QUOTENAME() function examples

To fully understand how QUOTENAME() behaves in different scenarios, it helps to see the function in action. Below are practical examples that demonstrate its use with various quote characters, along with an edge case involving input length. We'll also cover how to safely build fully qualified names using schema and table identifiers.

Basic examples with different quote characters

The QUOTENAME() function can apply different delimiter styles, depending on the character you provide. SQL Server automatically adds both the opening and closing symbols and enforces input rules.

Square brackets (default)

SELECT QUOTENAME('sales data');
-- Output: [sales data]

Double quotes

SELECT QUOTENAME('order total', '"');
-- Output: "order total"

Single quotes

SELECT QUOTENAME('client-name', '''');
-- Output: 'client-name'

Curly braces

SELECT QUOTENAME('schema_object', '{');
-- Output: {schema_object}

Angle brackets

SELECT QUOTENAME('Q1-results', '>');
-- Output: <Q1-results>  

Edge case: Input exceeds 128 characters

QUOTENAME() strictly limits input length to 128 characters. If the input string exceeds this limit, it returns NULL.

DECLARE @long NVARCHAR(200) = REPLICATE('a', 129);
SELECT QUOTENAME(@long); -- NULL

This behavior is by design, preventing misuse or overflow in metadata-related operations.

QUOTENAME() with aliases and schema names

When constructing fully qualified object names, such as [schema].[table name], QUOTENAME() can be used twice to wrap each part of the name individually. This ensures each component is valid, even if it contains spaces or special characters.

DECLARE @schema NVARCHAR(50) = 'product sales';
DECLARE @table  NVARCHAR(50) = 'order details';

SELECT QUOTENAME(@schema) + '.' + QUOTENAME(@table);
-- [product sales].[order details]

This technique is especially useful in dynamic SQL, where table names and schema names are parameterized and may not follow standard naming conventions.

Comparison: QUOTENAME() vs REPLACE() vs STRING_ESCAPE()

While QUOTENAME(), REPLACE(), and STRING_ESCAPE() are all string-related functions in SQL Server, they serve distinct purposes. Understanding their differences is critical when building dynamic SQL, formatting JSON, or manipulating text.

Below is a table comparing them across key dimensions.

Feature QUOTENAME() REPLACE() STRING_ESCAPE()
Primary purpose Delimits identifiers safely (e.g., tables, columns) Replaces substrings within text Escapes special characters for structured formats (e.g., JSON)
Injection protection Yes, Blocks invalid identifiers in dynamic SQL No, Not intended for security Yes, Escapes input for JSON contexts
Typical use Referencing names with spaces, keywords, or symbols Substituting one string with another Preparing strings for JSON output (e.g., FOR JSON PATH)
Output behavior Adds symmetric delimiters (e.g., [name], "name") Returns modified string without delimiters Returns escaped string using format-specific rules
Input constraints Max 128 characters; fails on closing quote conflicts No length limit Requires a format argument (e.g., 'json')
Handles internal delimiter chars No, Input cannot contain the closing delimiter Yes, Replaces all matches Yes, Escapes internal characters (e.g., quotes, newlines)
Common in dynamic SQL Standard practice for identifiers Used for basic string assembly, not safe for identifiers Used when outputting safe JSON via FOR JSON queries
Category Identifier safety / metadata General string manipulation Format-specific string preparation
Example QUOTENAME('table name') = [table name] REPLACE('abcabc','a', 'x') = xbcxbc STRING_ESCAPE('{"key":"val"}', 'json') = {\\"key\\":\\"val\\"}

Key takeaways

  • Use QUOTENAME() for identifiers, especially in dynamic SQL. It defends against injection and ensures syntactic correctness.
  • Apply REPLACE() when modifying text content, not identifiers. It's fast, simple, and flexible for general-purpose string operations.
  • Choose STRING_ESCAPE() when generating JSON or structured formats, where escaping special characters is required to maintain valid syntax.

Each serves a specific role. Using the wrong one in the wrong context, especially in dynamic SQL, can lead to broken queries or security vulnerabilities.

Conclusion

When writing dynamic SQL or referencing non-standard identifiers, QUOTENAME() is the right tool for the job. It enforces syntactic correctness, mitigates injection risks, and ensures your scripts behave predictably, even when object names contain spaces, symbols, or reserved words. Used in combination with a professional IDE like dbForge Studio for SQL Server, it enables developers to build dynamic, secure, and maintainable SQL with precision and confidence.

Start a free trial of dbForge Studio for SQL Server and simplify your dynamic SQL workflows with safer, cleaner identifier handling.

FAQ

What is QUOTENAME in SQL Server?

The QUOTENAME() function in SQL Server safely wraps identifiers, such as table or column names, in delimiters like brackets or quotes. This helps avoid syntax errors when names include spaces, special characters, or reserved words.

Can I use single quotes in QUOTENAME()?

Yes, but use them with caution. QUOTENAME() supports single quotes (') as a delimiter, but they are rarely used because they conflict with how SQL represents string literals. Square brackets ([ ]) or double quotes (" ") are safer and more conventional for identifiers.

How do I quote column names dynamically in SQL Server?

Use QUOTENAME() to wrap column names safely when building dynamic SQL. This prevents errors if the name contains spaces, special characters, or reserved words.

SET @sql = 'SELECT ' + QUOTENAME(@ColumnName) + ' FROM MyTable';
How is QUOTENAME() different from REPLACE() in SQL Server?

QUOTENAME() wraps identifiers in delimiters, ensuring they're syntactically valid. REPLACE() substitutes characters or substrings but offers no protection against syntax errors or SQL injection. Use QUOTENAME() when working with dynamic identifiers; REPLACE() is for manipulating text.

What does the QUOTENAME function do?

It adds delimiters (by default, square brackets) around a string to make it a valid SQL Server identifier. This is especially useful when dealing with names that include spaces, symbols, or reserved words.

What is the input limit for QUOTENAME()?

QUOTENAME() accepts input strings up to 128 characters. If the input exceeds this limit, it returns NULL.