返回

浏览器本地 SQL 工作台

数据互转

正在载入

正在加载工具

工具代码会在打开时按需载入,请稍候。

本工具的全部运算都发生在你的浏览器中,输入内容不会发送到任何服务器。

关于这个工具

把 CSV 或扁平 JSON 数组导入具名临时表,再用真实的 SQLite SQL 筛选、关联、分组和排序。CSV 单元格保持文本,包括前导零;JSON 基本值保留支持的数值、文本和 NULL 类型。sql.js 引擎在本地 Web Worker 中执行,工具不会上传输入、访问数据中的网址或保存输入历史。随站点打包的同源 SQLite WASM 资源为 658,410 字节(约 643 KiB),另有 Worker JavaScript;只有明确执行载入操作后才会获取。表只存在于当前页面的临时会话中。本工作台接收 CSV/JSON 表并执行只读查询;打开 SQLite 数据库文件或 Parquet 文件不在本工具范围内。

常见用途

  • 把订单 CSV 与客户 JSON 对照表关联,用 LEFT JOIN 保留没有匹配客户的订单。
  • 筛选导出数据,明确转换数字文本,按部门或地区聚合,并下载核对后的结果。
  • 检查 JSON 缺失值、比较字符串标识符,或用 WITH 公共表表达式编写清晰的多步查询。

使用方法

  1. 1.选择 CSV 或 JSON,输入唯一表名,粘贴文本或选择本地文件并指定 UTF-8、UTF-16LE 或 UTF-16BE。CSV 需明确选择逗号、分号、制表符或竖线及是否含表头。添加最多 8 个来源草稿,批量载入后查看每张表的列名和行数。任一来源无效都会阻止整批导入,不会悄悄跳过。JSON 必须是扁平对象数组;嵌套数据应先单独转换。
  2. 2.使用显示的表名和列名编写一条 SELECT 查询,可由 WITH 开头。含空格或标点的标识符使用双引号。CSV 中的数字是文本:先确认其为有效数字,再使用 CAST。添加 ORDER BY 获得可重现的顺序,用 WHERE 或 LIMIT 将结果限制在声明的范围内,然后运行。
  3. 3.下载 CSV 前核对结果行数和分页预览。公式防护默认开启;只有读过风险提示后才明确选择原始 CSV。导出包含成功结果的全部有界数据,而不只是当前页。取消或重置会释放 Worker 并丢弃所有已导入的表,继续使用时需重新导入来源。

可执行的 CSV 与 JSON SQL 示例

筛选数字文本并保留编号

{
  "sources": [
    {
      "name": "stock",
      "format": "csv",
      "text": "id,units\n001,12\n002,3\n010,20",
      "delimiter": ",",
      "header": true
    }
  ],
  "sql": "SELECT id, units FROM stock WHERE CAST(units AS INTEGER) >= 10 ORDER BY CAST(units AS INTEGER) DESC",
  "safe": true
}
{
  "columns": [
    "id",
    "units"
  ],
  "rows": [
    [
      "010",
      "20"
    ],
    [
      "001",
      "12"
    ]
  ]
}

CAST 改变比较方式,不改变选出的 id 或 units 字符串。返回编号仍是 010 和 001;显式 ORDER BY 将 20 排在 12 前面。

导入 JSON 布尔值、数字和缺失键

{
  "sources": [
    {
      "name": "tickets",
      "format": "json",
      "text": "[{\"id\":\"T1\",\"open\":true,\"score\":4.5},{\"id\":\"T2\",\"open\":false,\"score\":null},{\"id\":\"T3\",\"open\":true}]",
      "delimiter": ",",
      "header": true
    }
  ],
  "sql": "SELECT id, open, score FROM tickets ORDER BY id",
  "safe": true
}
{
  "columns": [
    "id",
    "open",
    "score"
  ],
  "rows": [
    [
      "T1",
      1,
      4.5
    ],
    [
      "T2",
      0,
      null
    ],
    [
      "T3",
      1,
      null
    ]
  ]
}

JSON true/false 变为 1/0,4.5 保持数值,明确的 null 与缺失的 score 键都得到 SQL NULL。编号字符串不变。

将 CSV 左连接到 JSON 对照表

{
  "sources": [
    {
      "name": "orders",
      "format": "csv",
      "text": "order_id,customer_id,total\nA100,001,12.50\nA101,002,0\nA102,009,7",
      "delimiter": ",",
      "header": true
    },
    {
      "name": "customers",
      "format": "json",
      "text": "[{\"id\":\"001\",\"name\":\"Alice\"},{\"id\":\"002\",\"name\":\"ボブ\"}]",
      "delimiter": ",",
      "header": true
    }
  ],
  "sql": "SELECT o.order_id, c.name, o.total FROM orders AS o LEFT JOIN customers AS c ON o.customer_id = c.id ORDER BY o.order_id",
  "safe": true
}
{
  "columns": [
    "order_id",
    "name",
    "total"
  ],
  "rows": [
    [
      "A100",
      "Alice",
      "12.50"
    ],
    [
      "A101",
      "ボブ",
      "0"
    ],
    [
      "A102",
      null,
      "7"
    ]
  ]
}

两个来源的客户编号均为字符串。未匹配的订单 A102 仍在结果中,客户名为 NULL,原始 total 仍是文本。

对已校验的整数金额分组求和

{
  "sources": [
    {
      "name": "sales",
      "format": "csv",
      "text": "region,amount\nEast,10\nWest,7\nEast,20",
      "delimiter": ",",
      "header": true
    }
  ],
  "sql": "SELECT region, SUM(CAST(amount AS INTEGER)) AS total, COUNT(*) AS records FROM sales GROUP BY region ORDER BY region",
  "safe": true
}
{
  "columns": [
    "region",
    "total",
    "records"
  ],
  "rows": [
    [
      "East",
      30,
      2
    ],
    [
      "West",
      7,
      1
    ]
  ]
}

SUM 前明确将 amount 转为整数。East 两条记录合计 30,West 一条合计 7。此例使用整数,不宣称精确十进制运算。

用 WITH 查询筛选聚合结果

{
  "sources": [
    {
      "name": "sales",
      "format": "csv",
      "text": "region,amount\nEast,10\nWest,7\nEast,20",
      "delimiter": ",",
      "header": true
    }
  ],
  "sql": "WITH totals AS (SELECT region, SUM(CAST(amount AS INTEGER)) AS total FROM sales GROUP BY region) SELECT region, total FROM totals WHERE total >= 10 ORDER BY region",
  "safe": true
}
{
  "columns": [
    "region",
    "total"
  ],
  "rows": [
    [
      "East",
      30
    ]
  ]
}

公共表表达式先计算各地区合计,外层 SELECT 只保留不少于 10 的合计。WITH 属于同一条只读语句。

按数值排序,同时保留原始写法

{
  "sources": [
    {
      "name": "items",
      "format": "csv",
      "text": "id,quantity\nA,10\nB,2\nC,001",
      "delimiter": ",",
      "header": true
    }
  ],
  "sql": "SELECT id, quantity, CAST(quantity AS INTEGER) AS numeric_quantity FROM items ORDER BY CAST(quantity AS INTEGER), id",
  "safe": true
}
{
  "columns": [
    "id",
    "quantity",
    "numeric_quantity"
  ],
  "rows": [
    [
      "C",
      "001",
      1
    ],
    [
      "B",
      "2",
      2
    ],
    [
      "A",
      "10",
      10
    ]
  ]
}

CAST 提供数值排序与数值输出列。原始数量 001 仍保留为 001,旁边显示它的数值解释 1。

引用含空格和 Unicode 的标识符

{
  "sources": [
    {
      "name": "商品",
      "format": "csv",
      "text": "名称,unit price\n猫,12.50",
      "delimiter": ",",
      "header": true
    }
  ],
  "sql": "SELECT \"名称\", \"unit price\" AS price FROM \"商品\"",
  "safe": true
}
{
  "columns": [
    "名称",
    "price"
  ],
  "rows": [
    [
      "猫",
      "12.50"
    ]
  ]
}

双引号引用表 商品 和列 unit price。值 猫 与价格字符串 12.50 原样返回;单引号则会创建字符串常量。

查询带引号的多行 CSV 字段

{
  "sources": [
    {
      "name": "notes",
      "format": "csv",
      "text": "id,note\n001,\"first\nsecond\"\n002,\"comma, quote \"\"ok\"\"\"",
      "delimiter": ",",
      "header": true
    }
  ],
  "sql": "SELECT id, note FROM notes ORDER BY id",
  "safe": true
}
{
  "columns": [
    "id",
    "note"
  ],
  "rows": [
    [
      "001",
      "first\nsecond"
    ],
    [
      "002",
      "comma, quote \"ok\""
    ]
  ]
}

解析遵循 CSV 记录边界:第一条备注内的换行仍属于一个值,成对双引号被还原为字面引号。

分别统计 NULL 与空字符串

{
  "sources": [
    {
      "name": "entries",
      "format": "json",
      "text": "[{\"id\":\"A\",\"value\":\"\"},{\"id\":\"B\",\"value\":null},{\"id\":\"C\"}]",
      "delimiter": ",",
      "header": true
    }
  ],
  "sql": "SELECT COUNT(*) AS records, COUNT(value) AS non_null, SUM(value IS NULL) AS nulls FROM entries",
  "safe": true
}
{
  "columns": [
    "records",
    "non_null",
    "nulls"
  ],
  "rows": [
    [
      3,
      1,
      2
    ]
  ]
}

共三行,但只有一个非 NULL 值,即空字符串。明确的 JSON null 和缺失键都满足 IS NULL。

使用无表头 CSV 的生成列名

{
  "sources": [
    {
      "name": "people",
      "format": "csv",
      "text": "001;Paris\n002;東京",
      "delimiter": ";",
      "header": false
    }
  ],
  "sql": "SELECT column1 AS id, column2 AS city FROM people ORDER BY column1",
  "safe": true
}
{
  "columns": [
    "id",
    "city"
  ],
  "rows": [
    [
      "001",
      "Paris"
    ],
    [
      "002",
      "東京"
    ]
  ]
}

关闭表头并选择分号后,两行都属于数据。导入器生成 column1 和 column2,SELECT 别名为结果提供有意义的表头。

默认保护疑似公式的表头和值

{
  "sources": [
    {
      "name": "sheet",
      "format": "csv",
      "text": "note,total\n=1+1,-42\n@SUM(A1),0",
      "delimiter": ",",
      "header": true
    }
  ],
  "sql": "SELECT note AS \"=header\", total FROM sheet ORDER BY total",
  "safe": true
}
{
  "columns": [
    "=header",
    "total"
  ],
  "rows": [
    [
      "=1+1",
      "-42"
    ],
    [
      "@SUM(A1)",
      "0"
    ]
  ],
  "csvRecords": [
    [
      "'=header",
      "total"
    ],
    [
      "'=1+1",
      "'-42"
    ],
    [
      "'@SUM(A1)",
      "0"
    ]
  ]
}

查询结果行不变。csvRecords 展示导出防护如何给 =header 列名、疑似公式文本及 -42 添加单引号。普通 CSV 引号并不能阻止公式。

仅为可信目标明确选择原始 CSV

{
  "sources": [
    {
      "name": "sheet",
      "format": "csv",
      "text": "note,total\n=1+1,-42",
      "delimiter": ",",
      "header": true
    }
  ],
  "sql": "SELECT note AS \"=header\", total FROM sheet",
  "safe": false
}
{
  "columns": [
    "=header",
    "total"
  ],
  "rows": [
    [
      "=1+1",
      "-42"
    ]
  ],
  "csvRecords": [
    [
      "=header",
      "total"
    ],
    [
      "=1+1",
      "-42"
    ]
  ]
}

safe 为 false 时,csvRecords 与查询结果及表头完全一致。这种输出可能在电子表格中执行公式,因此选择原始导出前必须主动核对。

本地 SQL 常见错误

  • 把 CSV 数字文本当成已经是数值类型的列进行比较或排序。
  • 用 CAST 代替校验,意外把错误数字文本转换为零。
  • 使用 = NULL 而不是 IS NULL,或把 COUNT(column) 当成总行数。
  • 关联非唯一键,导致输出行数意外倍增。
  • 给列名加单引号,而不是标识符所需的双引号。
  • 导入嵌套 JSON、重复键,或没有加引号且超出 JavaScript 安全范围的整数。
  • 以为取消 Worker 后导入表仍会保留,或过大查询失败后仍能导出部分结果。
  • 在电子表格中打开不可信原始 CSV,或误以为 CSV 引号能阻止公式。

限制与说明

  • 每个来源最多 2 MiB 原始文件字节和 2 MiB 解码后的 UTF-8 文本、10,000 数据行、128 列及 200,000 数据单元格。会话最多保留 8 张表,合计 8 MiB 原始来源字节和 8 MiB 解码后的 UTF-8 文本、50,000 行和 500,000 单元格。表名与列名不得为空,且最多 128 UTF-8 字节;仅 ASCII 大小写不同的名称冲突,以 sqlite_ 开头的表名保留。SQLite 原生分配上限为 64 MiB,数据库页上限为 32 MiB。解析后的输入、JavaScript 副本和 Worker 消息还会占用额外内存;这些并非浏览器总堆内存上限。
  • 文件需明确选择 UTF-8、UTF-16LE 或 UTF-16BE 编码;错误字节和冲突的 BOM 会被拒绝。CSV 使用明确的分隔符。不等宽记录、错误引号、空白或重复表头会导致导入失败;不自动识别分隔符或传统编码。无表头列命名为 column1、column2 等。CSV 值始终为 TEXT,包括空字符串和看似数字的编号。为防止值被悄悄改写,导入文本中的 NUL 字符和未配对的 UTF-16 代理项会被拒绝。JSON 接受扁平对象数组,按首次出现顺序合并键,将缺失值和 JSON null 映射为 SQL NULL,布尔值映射为 1/0。嵌套值、重复对象键、不安全整数及不支持的有精度损失数字记法会被拒绝;精确编号和小数应以带引号的 JSON 字符串提供。
  • 查询使用 SQLite 语法,必须是单条 SELECT 或 WITH…SELECT,最多 20,000 UTF-8 字节。不支持写入、PRAGMA、ATTACH、SQL 扩展、文件或网络访问、绑定参数及多条语句。结果最多 1,000 行、128 列、50,000 单元格、合计 2 MiB,单元格最多 256 KiB。超过任一结果限制会使查询失败,不保留部分结果或导出;请收紧 WHERE、减少选择的列或添加 LIMIT。预览每页 25 行,最多显示 12 列,每个单元格 500 字符;成功导出保留完整的有界结果。
  • 类型转换与比较遵循 SQLite 规则。CAST 可能把无效数字文本变成零,超出有符号 64 位范围的 INTEGER 转换会饱和为边界值,因此计算前应校验数据。小数运算使用二进制浮点,并非精确十进制记账。超出 JavaScript 安全整数范围的 64 位整数查询结果以精确十进制字符串表示;BLOB 结果显示并导出为大写 X'hex' 文本,而非原始字节。没有 ORDER BY 时不保证行序。重复关联键可能使结果行数成倍增加;LIMIT 限制返回行数,但不能保证查询成本很低。
  • CSV 输出最多 6 MiB,使用 UTF-8、逗号、带引号字段和 CRLF 记录分隔符,下载名为 sql-result.csv。SQL NULL 写为空字段,与空字符串的区别会丢失。公式防护会给风险表头和值添加单引号前缀,包括负数,并有意改变这些导出值。它无法阻止所有电子表格解释行为;原始 CSV 可能激活公式或转换编号。每次载入、查询、翻页或导出限时 10 秒。取消、超时、Worker 故障、修改来源、重置或离开工具都会丢弃内存中的所有表与结果;下载文件仍留在设备上且可能含私密信息。本工具不会创建数据库文件、外部扩展、远程表或保存的查询历史。

常见问题

为什么 CSV 的 ORDER BY 把 10 排在 2 前面?

CSV 列按文本导入,以保留 001 这类编号的原始写法。文本排序逐字符比较。确认数据是有效数字后,可用 ORDER BY CAST(quantity AS INTEGER) 或 CAST(amount AS REAL)。若原始字符串重要,请在 SELECT 中保留原列。CAST 不是校验:无效数字文本可能悄悄变成零。

空 CSV 字段和 JSON null 有何区别?

空 CSV 字段是空文本字符串。JSON null 与对象中缺失的键都映射为 SQL NULL;true 与 false 映射为 1 和 0。应使用 IS NULL,而非 = NULL。COUNT(column) 跳过 NULL,COUNT(*) 则计算行数。CSV 导出把 NULL 和空字符串都写为空字段,因此下载后无法区分两者。

能修改表、打开数据库文件或使用 SQL 参数吗?

导入控件会建立本地临时表,提交的 SQL 仅限单条只读查询。在资源限制内支持 SELECT、关联、聚合及 WITH…SELECT。INSERT、UPDATE、DELETE、CREATE、DROP、PRAGMA、ATTACH、绑定参数与扩展加载均被拒绝。本工具不打开 SQLite 数据库文件或 Parquet 文件;SQLite SQL 也不与所有其他数据库方言完全互通。

取消操作或查询结果过大时会怎样?

取消会终止 Worker,释放整个临时数据库及所有导入表,而不仅仅停止当前查询。重置或离开工具也会丢弃会话;继续使用需重新导入。超过行、列、单元格或字节限制的结果直接失败,不提供部分下载。请增加筛选、减少选择列或明确添加 LIMIT。仅预览被裁剪时,不会缩短成功的导出。

相关工具