/

SQL Parameter Replacer

Processed Client Side

Paste a parameterised SQL script and its parameter values, and get the final script back with every placeholder replaced by a correctly quoted literal — ready to paste into a client and run.

Script (top) · Parameter values (bottom)
SQLLength: 444Lines: 16Size: 444 BytesCursor: 1:1
name = valueLength: 202Lines: 9Size: 202 BytesCursor: 1:1
Final script
Ready to execute
SQLLength: 449Lines: 16Size: 449 BytesCursor: 1:1
No dialect markers — using standard SQL9 placeholdersStyle: :name1 placeholder-shaped run inside string literals or comments was left alone
:status'paid':start_date'2026-01-01':end_date'2026-04-01':countries('US', 'GB', 'DE'):min_total100:page_size50:reviewer'O''Brien':nowCURRENT_TIMESTAMP:order_id8241

Bookmark this tool now — skip the search next time you need it.

About SQL Parameter Replacer

This tool runs entirely in your browser. Whatever you paste is processed on your own device and is never uploaded, logged, or sent to any server.

A parameterised query is not something you can run. The log line says `WHERE status = ? AND created_at >= ?`, the ORM prints `:status` and `:start_date`, and the values sit somewhere else entirely — so reproducing what the application actually executed means splicing them back in by hand, getting the quoting right, and hoping you did not miss one. This tool does that splice: paste the script in the top pane, the values in the bottom pane, and the right-hand pane holds a script you can paste straight into a client and run. It reads :name, @name, ?, $1, {{name}}, ${name}, #{name} and %(name)s, quotes each value the way your engine expects, and tells you about any placeholder you left unbound before you find out from an error.

Key features

  • Nine placeholder styles recognised at once, or one pinned from the toolbar: :name, @name, ?, $1, {{name}}, ${name}, #{name}, %(name)s, %s, plus Oracle &name on request
  • Placeholders inside string literals, quoted identifiers and comments are left untouched — a query containing the text ‘:status’ in a WHERE clause is not rewritten
  • Values typed automatically: numbers stay bare, strings get quoted, true/false become TRUE/FALSE or 1/0 depending on the engine, and an empty value becomes NULL
  • A JSON array binds to an IN list — ["US","GB"] becomes (‘US’, ‘GB’) so `IN :countries` works as written
  • Backticks are the escape hatch: `CURRENT_TIMESTAMP` is injected as SQL rather than quoted as a string, which is how you bind an expression, a column, or a table name
  • Quotes inside values are escaped for the dialect — O’Brien becomes ‘O’’Brien’, and a backslash is doubled for MySQL and left alone everywhere else
  • Parameters accepted as a JSON object, a JSON array, or plain name = value lines with # and -- comments
  • Positional styles bind in order of appearance, and numbered ones ($1, ?3, :2) bind by their own number even when they repeat
  • Every substitution shown as a chip — placeholder, value, and how many times it appeared — with unbound ones flagged in red in both panes
  • Unused parameters reported too, which is usually a typo in a name rather than a spare value
  • "Fill from script" writes a JSON parameter set covering every placeholder, keeping the values already entered
  • Dialect detected from the script, upload a .sql file, copy or download the result, and nothing is ever uploaded

How to use it

  1. Paste the parameterised script into the top-left pane, or upload a .sql file.
  2. Put the values in the bottom-left pane: one name = value per line, or a JSON object. Click "Fill from script" to have every placeholder listed for you.
  3. Leave Dialect on Auto detect, or pick one if the script has no dialect-specific syntax.
  4. Leave Placeholder style on Auto detect unless your script uses Oracle &name, or a style you want pinned so nothing else matches.
  5. Read the chips under the panes to confirm what each placeholder became, and look for anything marked red or reported as unused.
  6. Copy the final script or download it as .sql, then run it.

Tips & common mistakes

  • Quoting is how you override the type guess. `id = 007` binds the number 7; `id = "007"` binds the string and keeps the zeros. Switch Values to "always quote" to do that for every parameter at once, which is what you want against CHAR key columns.
  • Backticks bind SQL, not a value. `now = `CURRENT_TIMESTAMP`` produces `CURRENT_TIMESTAMP` unquoted; without them you would get the string ‘CURRENT_TIMESTAMP’, which is not a timestamp. The same trick binds a table name, a column, or a whole subquery.
  • Write `IN :ids` rather than `IN (:ids)` and give ids a JSON array — the list literal brings its own parentheses. An empty array comes out as (NULL) with a warning, because IN () is a syntax error in every engine.
  • Escaping is dialect-specific in exactly one place that bites: MySQL reads a backslash inside a literal as an escape by default, so a Windows path or a regex is doubled for MySQL and left alone for PostgreSQL, SQLite, SQL Server and Oracle. Set the dialect before you trust a value containing a backslash.
  • The output is a script you are about to run, not a substitute for a prepared statement. Binding values in the driver is what stops SQL injection; this tool exists for the other job — reproducing, reviewing, or hand-running a query whose values you already have.
  • A count that looks wrong is nearly always a style collision. `?` is also a PostgreSQL jsonb operator and `&` is bitwise AND, so pin the style in the toolbar when Auto detect claims placeholders your script does not have.
  • Names are matched case-sensitively first. A parameter set exported as USER_ID still binds to :user_id, but the tool says it ignored case rather than doing it quietly — real drivers would not.
  • Nothing inside a string literal or a comment is ever substituted, and the status row counts what it skipped. If a placeholder you expected went unbound, check it is not sitting inside quotes.
  • Oracle &name is off unless you select it, because & is bitwise AND elsewhere and `flags&mask` would read as a substitution variable. SQL*Plus substitution is textual, so "never quote" or a backtick value usually matches what it means.

Related tools

Browse all 3 Database tools

Frequently asked questions

10

Paste the parameterised script into the top-left pane and its values into the bottom-left pane, either as name = value lines or as a JSON object. The finished script appears on the right immediately and updates as you type, with every placeholder replaced by a properly quoted literal. Copy it or download it as .sql and run it — nothing is uploaded, so this is safe to use on production queries.

Named styles :name, @name, {{name}}, ${name}, #{name} and %(name)s, and positional styles ?, $1 and %s — which covers JDBC, Oracle, SQLAlchemy, Hibernate, psycopg2, node-postgres, ADO.NET, MyBatis and Metabase. Oracle SQL*Plus &name is supported too but has to be chosen from the toolbar. Auto detect recognises all of them at once and reports which one it matched.

Three formats, detected automatically. A JSON object binds by name, a JSON array binds by position, and plain lines of name = value (or name: value) work for anything you are typing by hand. Blank lines are ignored and comment lines are skipped — `--`, `//`, or `#` followed by a space — so you can annotate a parameter set. A `#` with no space after it is a value, so a colour like #FF0000 survives.

Yes, and that is most of the work. Numbers stay bare, strings are wrapped in single quotes with any inner quote doubled, booleans become TRUE/FALSE — or 1/0 on SQL Server and Oracle, which have no boolean literal — and an empty value becomes NULL. For MySQL a backslash inside a value is also doubled, because MySQL reads it as an escape character while the other engines do not.

Give the parameter a JSON array and write the placeholder without parentheses: `WHERE id IN :ids` with `ids = [1, 2, 3]` produces `IN (1, 2, 3)`, because the list literal supplies its own brackets. An empty array is written as (NULL), which matches nothing, since IN () is not valid SQL in any engine.

Wrap the value in backticks and it is injected as SQL rather than quoted as a string. `now = `CURRENT_TIMESTAMP`` gives you CURRENT_TIMESTAMP in the output, not the eleven-character string. The same works for a column name, a table name, or an entire subquery. To do it for every parameter at once, set Values to "never quote".

No. The script is split into code and non-code before anything is matched, so text inside string literals, quoted identifiers and comments is never touched — a query containing ‘:status’ as a literal survives intact, and the status row tells you how many such runs it skipped. PostgreSQL’s :: cast and array slices like a[1:3] are excluded for the same reason.

By default it is left exactly as written and flagged in red in both panes and in the chip row, so an incomplete script is obvious rather than silently wrong. Switch Missing to "bind NULL" if you would rather have every placeholder filled. Parameters you supplied that the script never uses are reported too, which usually means a name is misspelled on one side.

No, and it should not replace one. Prepared statements are what protect you from SQL injection, because the values never become part of the statement text. This tool does the opposite on purpose — it produces the final text — which is what you want for reproducing a logged query, reviewing what an ORM sent, or running a parameterised migration by hand.

No. The scanner, the value parser and the substitution all run as JavaScript in your browser tab, and there is no request that sends a query or a value anywhere. That is what makes it safe to paste a production query along with the real customer identifiers you were about to bind into it.