/^/
MediumProgramming5 min read

SQL Identifier Regex

Validates a SQL identifier (table or column name) in any of its common forms: a plain unquoted identifier, a double-quoted identifier (ANSI SQL/PostgreSQL), a backtick-quoted identifier (MySQL), or a bracket-quoted identifier (SQL Server).

#sql#identifier#database#programming#syntax

Regex Pattern

^(?:[A-Za-z_][A-Za-z0-9_]*|"[^"]*"|`[^`]*`|\[[^\]]*\])$

Pattern Breakdown

Hover over a token to see what it does.

^(?:[A-Za-z_][A-Za-z0-9_]*|"[^"]*"|`[^`]*`|\[[^\]]*\])$
TokenMeaning
^(?:Start of the string, followed by a non-capturing group of alternative identifier forms
[A-Za-z_][A-Za-z0-9_]*An unquoted identifier: starts with a letter or underscore, continues with letters, digits, or underscores
"[^"]*"A double-quoted identifier: any characters except a double quote, wrapped in double quotes (ANSI SQL / PostgreSQL style)
`[^`]*`A backtick-quoted identifier: any characters except a backtick, wrapped in backticks (MySQL style)
\[[^\]]*\]A bracket-quoted identifier: any characters except ']', wrapped in square brackets (SQL Server style)
)$Closes the alternation group and anchors it to the end of the string

Detailed Explanation

What it does

This pattern checks whether a string is a valid SQL identifier in any of the four common dialect-specific shapes: a plain unquoted name, or a name wrapped in double quotes, backticks, or square brackets, which different database engines use to allow reserved words, spaces, or mixed case in identifiers.

Why it works

Different SQL dialects quote identifiers differently: standard SQL and PostgreSQL use double quotes, MySQL uses backticks, and SQL Server uses square brackets, while every dialect also accepts a plain unquoted name following the classic letter-or-underscore-then-word-characters rule. The four alternatives inside the non-capturing group cover each style, each restricting its inner content to exclude its own delimiter character, and the ^/$ anchors ensure the entire string is exactly one such identifier.

Common use cases

  • Validating a column or table name before interpolating it into a dynamically built SQL query
  • Linting a schema migration file for identifiers that use the wrong quoting style for the target database
  • Building a query builder or ORM that needs to detect whether a name requires quoting
  • Sanitizing user-supplied sort/filter field names before using them in a query fragment

Edge cases

  • A quoted identifier containing a space, like "Order Date" or [Order Date], is valid since spaces are only disallowed in the unquoted form
  • A quoted identifier that happens to look like a reserved word, like `order` or "select", is valid because quoting exempts it from keyword restrictions
  • An unquoted identifier starting with a digit, like 123column, is rejected since none of the four alternatives allow a bare leading digit
  • An identifier with a hyphen and no quoting, like user-id, is rejected because hyphens are not part of the unquoted identifier character set

Limitations

  • Does not handle escaped delimiter characters inside a quoted identifier (e.g. doubled quotes like """ "" to represent a literal quote)
  • Does not enforce per-database maximum identifier length limits (e.g. 128 characters in SQL Server, 63 bytes in PostgreSQL)
  • Does not check for reserved-keyword collisions in the unquoted form; some engines reject unquoted reserved words even though they match this pattern's shape

Interactive Tester

Edit the pattern or text below — matching runs live in your browser.

user_id _temp "My Column"

Test Cases

Editable — add your own inputs to see if they pass.

InputExpectedResult
Pass
Pass
Pass
Pass
Pass
Pass
Pass
Pass
Pass

Language Variants

Production-ready examples in 12 languages.

const sqlIdentifierRegex = /^(?:[A-Za-z_][A-Za-z0-9_]*|"[^"]*"|`[^`]*`|\[[^\]]*\])$/;
console.log(sqlIdentifierRegex.test('`order`')); // true

Common Mistakes

Writing a pattern that only supports one dialect's quoting style, then rejecting valid identifiers from other database engines (e.g. rejecting `backtick` names when only double quotes were considered)

Fix: Include all the quoting alternatives your application needs to support (double quotes, backticks, brackets) in the alternation

Allowing digits in the first character of the unquoted form, e.g. [A-Za-z0-9_][A-Za-z0-9_]*, which incorrectly accepts identifiers like 123table

Fix: Keep the unquoted form's first character restricted to [A-Za-z_] with no digits

Not accounting for escaped delimiters inside quoted identifiers (like a doubled double-quote to represent a literal quote character), causing valid dialect-specific identifiers to be rejected

Fix: Extend the quoted alternatives to allow the dialect's specific escape sequence if your application needs to support it

Performance Notes

  • Each alternative in the group is anchored to a distinct starting character (letter/underscore, quote, backtick, or bracket), so the engine can often reject non-matches after checking just the first character
  • The negated character classes inside the quoted forms ([^"]*, [^`]*, [^\]]*) avoid backtracking since they stop precisely at their own delimiter
  • Cheap enough to validate every identifier in a large generated SQL statement without measurable overhead

Browser Compatibility

EngineSupportedNotes
ChromeYes
FirefoxYes
SafariYes
EdgeYes
Node.jsYes