What the error means
SQL string literals are delimited by single quotes. When the parser sees an opening quote, everything up to the next single quote is the string. Unclosed quotation mark after the character string — SQL Server's full wording, shortened to Unclosed quotation mark by most tools — means the parser reached the end of the statement while still inside a string. PostgreSQL phrases the same failure as unterminated quoted string.
The example is the classic case. The parser reads 'O' as a complete two-character string, then finds Brien (a syntax error in itself), then an opening quote before the semicolon that never closes. Which of those it reports first depends on the engine; either way the cause is the apostrophe in the name.
Why it happens
- An apostrophe inside a value: names like O'Brien, phrases like
it's, or possessives in free text. This is the overwhelming cause. - A quote that was deleted while editing a long WHERE clause.
- Typographic quotes (
‘’) pasted from a document. They are not', so the real quote pair is broken. - Building SQL by string concatenation in application code, where a value containing a quote is inserted raw. This is also an SQL injection hole, which matters more than the error.
- Mixing quote styles: using
"for a string literal, which in PostgreSQL and SQL Server denotes an identifier, not a string.
How to fix it
- Paste the statement into the formatter above. The highlighted output shows where the string actually starts and ends, which is usually not where you think.
- Inside a string literal, write a single quote as two single quotes:
'O''Brien'. This is standard SQL and works in every dialect. - Check that every opening quote has a closing one on the same statement.
- In application code, stop concatenating and use a parameterised query; the driver handles escaping and the injection risk disappears.
The corrected example:
SELECT * FROM users WHERE last_name = 'O''Brien';
If it still fails
- Replace any curly quotes with straight ones; String Escape in SQL mode doubles embedded quotes for you when preparing a literal by hand.
- MySQL also accepts
\'inside strings, but that is non-standard;''is portable. - A very long statement may report the error far from the cause. Minify it with SQL Minifier, then bisect: delete half the WHERE clause and see whether the error persists.
Related errors
syntax error at or near ","
Remove the trailing comma before FROM, WHERE, or a closing parenthesis; PostgreSQL reads the comma as the start of another item and then finds a keyword instead.
Incorrect syntax near ")"
Match every ( to a ), remove the extra closer, and never leave IN () or VALUES () empty; SQL Server reports the parenthesis it could not pair.