SQL to JSON Converter

Turn INSERT statements into an array of objects you can feed to an API, a fixture loader or a test. Types are decided once per column, so no key is a number on one row and a string on the next.

To convert SQL to JSON, paste your INSERT statements above. Each row becomes one object keyed by column name, and each column is given a single type decided from all of its values: real numbers, real booleans, real nulls, and strings for anything that would not survive the round trip. Choose pretty or minified output and download the file. Everything runs locally.

Want to reshape or nest the result? Open the app

Why the types are the whole job

Anyone can turn a row of SQL values into a row of JSON strings. The reason that is not good enough is that JSON is usually the last stop before something strict: a schema validator, a warehouse loader, a typed client generated from an OpenAPI document. Those things reject a payload where the same key is a number in one object and a string in the next, and they are right to.

So the type is decided once for the whole column. A column is numeric only when every non-empty value in it round trips exactly through a number: 42 qualifies, 1840.50 does not, because writing that back gives 1840.5. A column is boolean only when every value is a SQL TRUE or FALSE. Anything mixed stays a string, top to bottom.

The competing free converter on this exact term types each cell independently. Its own output has the same key as a string on one line and a number on the next, and every consumer it advertises on that page will refuse the load. That is the specific bug this page exists to not have.

Worked example: an orders table

Two rows from a dump, with a padded region code and a NULL:

INSERT INTO orders (order_id, region_code, customer, units, revenue, paid, note) VALUES
  (4101, '01', 'Ada Lovelace', 12, 1840.50, TRUE, NULL),
  (4103, '01', 'Grace Hopper', 40, 6120.75, FALSE, 'repeat');

And the JSON:

[
  {
    "order_id": 4101,
    "region_code": "01",
    "customer": "Ada Lovelace",
    "units": 12,
    "revenue": "1840.50",
    "paid": true,
    "note": null
  },
  {
    "order_id": 4103,
    "region_code": "01",
    "customer": "Grace Hopper",
    "units": 40,
    "revenue": "6120.75",
    "paid": false,
    "note": "repeat"
  }
]

Read that output against the input and every decision is visible. order_id and units are numbers because every value in them is an exact integer. region_code is a string because 01 would lose its zero. paid is a real boolean. note is null rather than an empty string, because the database distinguished those and so does this. And revenue is a string, which surprises people, so it gets its own section below.

Why the money column came out as text

1840.50 is a DECIMAL in the database. In JSON there is no decimal; there are only IEEE-754 doubles. Writing it as a number gives you 1840.5, which is a different string, and once one row in the column loses a trailing zero the column has stopped being trustworthy for anything that compares or displays it.

So the rule is exactness: a column becomes numeric only when every value writes back character for character. A price column of whole numbers and one-decimal values becomes numbers. A price column with a trailing zero anywhere in it stays strings, all the way down, and you keep the exact figure the database held.

Long identifiers are the same story from the other direction. A nineteen-digit snowflake ID does not survive a double, so a column of those stays strings and your IDs stay correct. If you would rather have numbers and can accept the rounding, cast the column in your query before you dump it.

Objects, or one per line

The default is a pretty-printed array of objects, which is what a fixture file or an API request body wants and what reads properly in a diff. The Structure switch turns that into JSON Lines instead: one compact object per line, no wrapping array, no commas between records.

JSON Lines is what BigQuery, Snowflake, DuckDB and most log shippers actually want for a bulk load, and it is what lets a consumer stream a million rows without holding the whole document in memory. Both shapes come out of the same typed table, so a column that is a string in one is a string in the other.

Dumps with more than one table

A JSON document is one array, so a dump carrying six tables cannot become one file without inventing a structure nobody asked for. Instead the tables are listed under the result with their row and column counts, the first converts on arrival, and picking another re-runs the conversion for that one.

That is a deliberate refusal. Nesting the tables into an object keyed by table name would look tidy and would be wrong for the two most common uses of this page, seeding a test database and posting rows to an endpoint, both of which want one array.

Frequently Asked Questions

Why is my revenue column a string instead of a number?

Because a value in it does not round trip. 1840.50 written back as a JSON number is 1840.5, a different string, so the whole column stays text rather than half the rows silently losing a trailing zero. A column whose every value survives exactly, like 12 or 1840.5, becomes numbers.

Does NULL become null or an empty string?

A real JSON null. The database distinguished a NULL from an empty string and so does this, because in almost every consumer that distinction decides whether a default applies. A quoted 'NULL' in the SQL stays the four-letter text.

Can I get one JSON object per line instead of an array?

Yes. The Structure switch emits JSON Lines: one compact object per line, no wrapping array. That is what BigQuery, Snowflake, DuckDB and most log shippers want for a bulk load, and it streams without holding the document in memory.

Are the types the same on every row?

Always. A type is decided once per column from all of its values, never per cell. That is the failure mode in most free converters on this term: the same key arrives as a number on one line and a string on the next, and any schema-checked consumer rejects the load.

What happens with a nineteen-digit ID?

It stays a string. JSON numbers are IEEE-754 doubles, so anything past about fifteen significant digits loses precision, and a snowflake ID that has been rounded is worse than useless. The column stays text and the ID stays correct.

My dump has eight tables. Which one do I get?

The first one converts immediately and the other seven appear as a picker under the result with their row and column counts. Nothing is silently dropped, and nothing is nested into an invented wrapper object either, because one array is what the two common uses of this page want.

Turn those INSERTs into typed JSON

One object per row, one type per column, real nulls. Nothing uploaded, nothing to sign up for.

Back to the converter