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
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.
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.
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';
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.
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.
QUOTENAME() accepts input strings up to 128 characters. If the input exceeds this limit, it returns NULL.