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).
Regex Pattern
^(?:[A-Za-z_][A-Za-z0-9_]*|"[^"]*"|`[^`]*`|\[[^\]]*\])$Pattern Breakdown
Hover over a token to see what it does.
| Token | Meaning |
|---|---|
| ^(?: | 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.
Test Cases
Editable — add your own inputs to see if they pass.
| Input | Expected | Result | |
|---|---|---|---|
| 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`')); // trueCommon 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
| Engine | Supported | Notes |
|---|---|---|
| Chrome | Yes | — |
| Firefox | Yes | — |
| Safari | Yes | — |
| Edge | Yes | — |
| Node.js | Yes | — |