“STRING_AGG is not a recognized built-in function name” shows up when your database, version, or SQL mode doesn’t include STRING_AGG, so you must switch dialects or use the right replacement.
This error usually hits during copy-paste. A query that runs in one database can fail in another, even when the SQL looks familiar. The reason is simple. Function lists vary by engine, and even the same engine can behave differently across versions or modes.
Your job is to figure out what’s actually running your query. Once you know that, the fix is often a small change, not a rewrite.
What This Error Means In Plain Words
STRING_AGG() is a “group then join” function. It collects many row values and returns one text value, separated by the delimiter you provide. Some engines ship it. Some ship a different name. Some ship it only in newer releases.
When the parser says the function name isn’t recognized, one of these is true.
- Your engine doesn’t have it — The database simply doesn’t include
STRING_AGGas a built-in function. - Your engine has it, but not your version — A newer tutorial can be correct while your server is older.
- Your SQL mode is wrong — The same product can run multiple dialects, and function availability can change with the mode.
- You copied syntax from another dialect — The name might exist, yet the options you added don’t match the engine’s rules.
Fixing this starts with one decision. Identify the engine and the mode that executed the query, not the tool that displayed the editor.
Quick Checks That Fix Most Cases
Run these checks in order. They’re quick and they narrow the problem fast.
- Confirm the engine — Check the connection details in your app, driver, or warehouse selector. Write down the engine name.
- Confirm the version — If you can run a query, grab the version string. In SQL Server use
SELECT @@VERSION. In Postgres useSHOW server_version. - Confirm the mode — Some tools can run different SQL modes. Make sure you’re not in a legacy mode that drops newer functions.
- Run a tiny test — Use a two-row inline dataset and call
STRING_AGG. If the tiny test fails, your issue is engine, version, or mode. - Simplify the call — Remove ordering or distinct options, get a clean run, then add features back one by one.
That tiny test is the fastest truth check. If STRING_AGG fails on two literals, your production tables aren’t the cause.
Fixing string_agg is not a recognized built-in function name In BigQuery
BigQuery works best with Standard SQL. When you see this error in BigQuery, the most common cause is that the query ran under Legacy SQL, or a connector forced Legacy SQL behind the scenes.
Force Standard SQL
Start by ensuring Standard SQL is active for the query you’re running. In the BigQuery UI this is normally the default for new queries, yet saved queries, scheduled jobs, and third-party tools can override it.
- Switch off Legacy SQL — In query settings, disable Legacy SQL for that query or job.
- Add a directive line — If your tool respects it, put
#standardSQLas the first line of the query. - Recheck scheduled jobs — Older scheduled queries can keep Legacy SQL settings even after UI defaults change.
Use A Clean BigQuery Pattern
Once Standard SQL is active, this is the basic pattern.
SELECT
user_id,
STRING_AGG(page, ', ') AS pages
FROM logs
GROUP BY user_id;
If you need ordering, build an array in the order you want, then join it into text. This keeps the intent obvious and avoids “random order” surprises.
- Collect ordered values — Use
ARRAY_AGG(page ORDER BY ts)to control order. - Join into text — Use
ARRAY_TO_STRINGto create one string with a delimiter.
When you only need a distinct list, try STRING_AGG(DISTINCT page, ', '). If distinct plus ordering gets messy, the array approach stays easier to reason about.
STRING_AGG Is Not A Recognized Built-In Function Name In Other Databases
Different engines solve the same task with different function names. Use this table to match your target database to the right approach.
| Database | Function To Use | Notes |
|---|---|---|
| SQL Server | STRING_AGG | Works in SQL Server 2017+; older versions need a workaround |
| Postgres | string_agg | Avoid quoting the function name; ordering syntax differs |
| MySQL | GROUP_CONCAT | Different syntax; watch max length limits |
| SQLite | group_concat | Ordering needs a subquery; delimiter is the second argument |
SQL Server
In SQL Server, STRING_AGG is available in SQL Server 2017 and later. If you’re on 2016 or older, you’ll see the error even when your syntax is perfect for modern versions.
- Check the version — Run
SELECT @@VERSIONand confirm the year. - Use a legacy pattern — Older servers often use
FOR XML PATHplusSTUFFto concatenate rows. - Add ordering the SQL Server way — On 2017+ you can use
WITHIN GROUP (ORDER BY ...)for stable ordering.
If you have multiple servers, double-check which one your app hits. It’s common for dev to be newer than prod.
Postgres
Postgres uses string_agg. Function names are case-insensitive unless you wrap them in double quotes. If you copied uppercase and quoted it, Postgres will treat it as a different name and fail.
- Drop double quotes — Use
string_agg(col, ', '), not"STRING_AGG"(col, ', '). - Sort inside the call — Postgres supports ordering inside
string_aggusing anORDER BYclause in the argument list. - Handle nulls on purpose — Most engines skip nulls, so use
COALESCEonly when you truly want placeholders.
MySQL And MariaDB
MySQL doesn’t provide STRING_AGG. The closest built-in is GROUP_CONCAT. The syntax is different, especially around separators.
SELECT
user_id,
GROUP_CONCAT(page ORDER BY page SEPARATOR ', ') AS pages
FROM logs
GROUP BY user_id;
Long lists can be cut off in MySQL unless you raise group_concat_max_len. If output looks truncated, check that setting early.
Edge Cases That Make A Correct Query Fail
After you pick the right function, a few details can still bite. These are the failures that feel confusing because the query looks “normal.”
- Wrong argument order — Many engines take the value first, separator second. Swapping them can trigger type errors.
- Mixed data types — Cast dates, numbers, and JSON to text before aggregation so the output format is predictable.
- Unstable ordering — Aggregates don’t promise order unless you ask for it using the engine’s ordering feature.
- Row multiplication from joins — A join can duplicate values and make your list look wrong. Fix the join first.
- Delimiter collisions — If values can contain commas, pick a safer delimiter or quote values consistently.
If your result list repeats values, validate the row set before the aggregation step. A quick COUNT(*) per key can show whether the join is multiplying rows.
A Copy-Paste Debug Template You Can Reuse
Use this checklist when you see the same error again. It keeps you moving and keeps the investigation tidy.
- Write down the backend — Engine name, version, and any SQL mode setting.
- Run a tiny repro — Two rows, one group, one aggregation call.
- Swap to the matching function — Use the right function name for that engine.
- Add features step by step — Start with a plain list, then add distinct, ordering, and casting.
- Recheck the connector path — If it works in the database console but fails in a tool, the tool may be rewriting SQL or switching dialect.
Also, keep one rule of thumb in mind. When your downstream code needs a list for filtering or further processing, returning an array can be cleaner than returning delimited text. Arrays reduce delimiter bugs and are easier to work with in many warehouses.
Finally, you asked for the main keyword to appear naturally in body text. Here it is in lowercase, exactly where it belongs: string_agg is not a recognized built-in function name. If you see it again, treat it as a routing or dialect mismatch first, then a syntax issue second.
