返回

CSV 透视与逆透视

数据互转

正在载入

正在加载工具

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

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

关于这个工具

把交易明细转换为按地区和月份汇总的宽表,或把逐月宽表展开为包含标识符、变量名和值的长表。透视支持多个行键、一个列键、多个值列以及明确选择的聚合方式;逆透视保留所选标识列,并按原始解析字符串复制各值。重复的透视坐标会参与聚合,不会悄悄覆盖前一行。精确十进制运算避免二进制浮点误差;不符合格式的数值文本会报错,不能表示为有限小数的平均值则输出 1/3 等精确最简分数字符串,不会自行猜测或舍入。解析、转换和导出均在浏览器本地工作线程中完成。

常见用途

  • 按地区和产品汇总销售明细,将月份展开为列,并对所选金额与数量列计算精确合计。
  • 按原样分类键统计非空观测值,同时保留 001、1 以及区分大小写的部门代码。
  • 把 Jan、Feb、Mar 列展开为变量名/值长表,供其他报表系统使用,同时保留账户编号、空单元格和原始小数写法。

使用方法

  1. 1.粘贴 CSV 文本或选择本地文件,设置分隔符、表头和支持的文件编码,再读取列信息。选择透视或逆透视。透视按需选择行键,再选择一个列键、一个或多个值列及聚合方式;这些角色不得重叠。逆透视选择要保留的标识列和要展开的值列,并设置变量名列与值列的输出名称。
  2. 2.运行前检查所选列。匹配键按原样字符串比较,不会自动去空白、忽略大小写或转为数字。数值聚合只接受说明中规定的十进制格式。逆透视默认保留空值与缺失值;只有确实要丢弃已存在的空字符串时,才选择丢弃空值。缺失的 null 值仍会保留。修改输入或设置会使此前结果失效。
  3. 3.执行转换,检查结果行列数和分页预览,再下载 JSON 或 CSV。分类值或原表头含有标点时,请查看输出列元数据。JSON 可区分 null 缺失值与空字符串,并保留字符串编号。供电子表格查看时建议启用 CSV 公式防护;只有确认目标可信时才显式选择原始 CSV。分页和缩短显示不会截断成功生成的完整导出。

透视与逆透视转换前后示例

按地区和产品透视精确销售合计

{
  "input": "region,product,month,amount,units\nNorth,001,Jan,0.10,2\nNorth,001,Jan,0.20,3\nNorth,001,Feb,1.50,1\nSouth,001,Jan,4,2\nNorth,1,Jan,2,1",
  "parseOptions": {
    "delimiter": ",",
    "header": true
  },
  "options": {
    "mode": "pivot",
    "rowKeys": [
      "region",
      "product"
    ],
    "columnKey": "month",
    "valueColumns": [
      "amount",
      "units"
    ],
    "aggregation": "sum"
  }
}
{
  "headers": [
    "region",
    "product",
    "pivot:[\"Jan\",\"amount\",\"sum\"]",
    "pivot:[\"Jan\",\"units\",\"sum\"]",
    "pivot:[\"Feb\",\"amount\",\"sum\"]",
    "pivot:[\"Feb\",\"units\",\"sum\"]"
  ],
  "rows": [
    [
      "North",
      "001",
      "0.3",
      "5",
      "1.5",
      "1"
    ],
    [
      "South",
      "001",
      "4",
      "2",
      null,
      null
    ],
    [
      "North",
      "1",
      "2",
      "1",
      null,
      null
    ]
  ]
}

转换前的 North/001/Jan 出现两次,因此 0.10 + 0.20 得到精确字符串 0.3,2 + 3 得到 5。月份按首次出现顺序排列,每个月依次输出 amount 与 units。North/001 与 North/1 仍是不同分组;没有观测记录的地区/产品/月组合为 null。

计数非空值,包括文本

{
  "input": "id,month,value\nA,Jan,yes\nA,Jan,\nA,Jan\nA,Feb,0\nB,Jan,",
  "parseOptions": {
    "delimiter": ",",
    "header": true
  },
  "options": {
    "mode": "pivot",
    "rowKeys": [
      "id"
    ],
    "columnKey": "month",
    "valueColumns": [
      "value"
    ],
    "aggregation": "count"
  }
}
{
  "headers": [
    "id",
    "pivot:[\"Jan\",\"value\",\"count\"]",
    "pivot:[\"Feb\",\"value\",\"count\"]"
  ],
  "rows": [
    [
      "A",
      "1",
      "1"
    ],
    [
      "B",
      "0",
      null
    ]
  ]
}

A/Jan 统计 yes,但跳过空字段与缺失字段;A/Feb 统计文本 0。B/Jan 有源坐标但没有非空观测,计数为 "0";B/Feb 没有源坐标,因此为 null。这既不是去重计数,也不是全部源行数。

计算精确的有限小数平均值

{
  "input": "id,month,value\nA,Jan,0.1\nA,Jan,0.2\nB,Jan,0.125\nB,Jan,0.375",
  "parseOptions": {
    "delimiter": ",",
    "header": true
  },
  "options": {
    "mode": "pivot",
    "rowKeys": [
      "id"
    ],
    "columnKey": "month",
    "valueColumns": [
      "value"
    ],
    "aggregation": "avg"
  }
}
{
  "headers": [
    "id",
    "pivot:[\"Jan\",\"value\",\"avg\"]"
  ],
  "rows": [
    [
      "A",
      "0.15"
    ],
    [
      "B",
      "0.25"
    ]
  ]
}

A 的 (0.1 + 0.2) / 2 精确等于 0.15;B 的 (0.125 + 0.375) / 2 精确等于 0.25。结果以十进制字符串输出,不引入二进制浮点近似。

从含负数的值中求最小值

{
  "input": "id,month,value\nA,Jan,-3.20\nA,Jan,7.50\nA,Jan,-0.00",
  "parseOptions": {
    "delimiter": ",",
    "header": true
  },
  "options": {
    "mode": "pivot",
    "rowKeys": [
      "id"
    ],
    "columnKey": "month",
    "valueColumns": [
      "value"
    ],
    "aggregation": "min"
  }
}
{
  "headers": [
    "id",
    "pivot:[\"Jan\",\"value\",\"min\"]"
  ],
  "rows": [
    [
      "A",
      "-3.2"
    ]
  ]
}

-3.20、7.50 和 -0.00 的数值最小值为 -3.2。聚合会规范化小数写法,并按精确数值比较,不是按文本排序。

求超出 JavaScript 安全整数范围的最大值

{
  "input": "id,month,value\nA,Jan,9007199254740992\nA,Jan,9007199254740993",
  "parseOptions": {
    "delimiter": ",",
    "header": true
  },
  "options": {
    "mode": "pivot",
    "rowKeys": [
      "id"
    ],
    "columnKey": "month",
    "valueColumns": [
      "value"
    ],
    "aggregation": "max"
  }
}
{
  "headers": [
    "id",
    "pivot:[\"Jan\",\"value\",\"max\"]"
  ],
  "rows": [
    [
      "A",
      "9007199254740993"
    ]
  ]
}

基于 BigInt 的比较仍能区分这两个大整数。精确最大值是字符串 9007199254740993,不会舍入为相邻的 JavaScript Number 可表示值。

以精确分数保留循环小数平均值

{
  "input": "id,month,value\nA,Jan,1\nA,Jan,0\nA,Jan,0",
  "parseOptions": {
    "delimiter": ",",
    "header": true
  },
  "options": {
    "mode": "pivot",
    "rowKeys": [
      "id"
    ],
    "columnKey": "month",
    "valueColumns": [
      "value"
    ],
    "aggregation": "avg"
  }
}
{
  "headers": [
    "id",
    "pivot:[\"Jan\",\"value\",\"avg\"]"
  ],
  "rows": [
    [
      "A",
      "1/3"
    ]
  ]
}

此处平均值为 1/3,不能表示为有限小数。转换后保留精确最简分数字符串 "1/3",不舍入,也不转为二进制浮点数。需要保留该表示时请使用 JSON。分数结果不属于后续数值聚合可接受的十进制输入。

拒绝把前导零编号当成数值

{
  "input": "id,month,value\nA,Jan,001",
  "parseOptions": {
    "delimiter": ",",
    "header": true
  },
  "options": {
    "mode": "pivot",
    "rowKeys": [
      "id"
    ],
    "columnKey": "month",
    "valueColumns": [
      "value"
    ],
    "aggregation": "sum"
  }
}
{
  "error": "numeric"
}

001 不符合数值求和规则,会返回 numeric,而不会变成 1。该文本仍可作为键、作为非空值计数,或由逆透视按原样复制。

逆透视前后保留原始值

{
  "input": "id,Jan,Feb\n001,1.00,\n1,,null\n002,0\n003, ,=1+1",
  "parseOptions": {
    "delimiter": ",",
    "header": true
  },
  "options": {
    "mode": "unpivot",
    "idColumns": [
      "id"
    ],
    "valueColumns": [
      "Jan",
      "Feb"
    ],
    "variableName": "month",
    "valueName": "amount",
    "dropEmpty": false
  }
}
{
  "headers": [
    "id",
    "month",
    "amount"
  ],
  "rows": [
    [
      "001",
      "Jan",
      "1.00"
    ],
    [
      "001",
      "Feb",
      ""
    ],
    [
      "1",
      "Jan",
      ""
    ],
    [
      "1",
      "Feb",
      "null"
    ],
    [
      "002",
      "Jan",
      "0"
    ],
    [
      "002",
      "Feb",
      null
    ],
    [
      "003",
      "Jan",
      " "
    ],
    [
      "003",
      "Feb",
      "=1+1"
    ]
  ]
}

Jan 和 Feb 按源行顺序展开为 month 行。编号 001、小数写法 1.00、空字符串、文本 null、缺失的 Feb 值、空白及类似公式的文本均保留解析后的值。此处不会执行公式文本;受保护的 CSV 会改动风险字段,JSON 则原样保留。

逆透视时只丢弃现有空字符串

{
  "input": "id,Jan,Feb\n001,1.00,\n1,,null\n002,0\n003, ,=1+1",
  "parseOptions": {
    "delimiter": ",",
    "header": true
  },
  "options": {
    "mode": "unpivot",
    "idColumns": [
      "id"
    ],
    "valueColumns": [
      "Jan",
      "Feb"
    ],
    "variableName": "month",
    "valueName": "amount",
    "dropEmpty": true
  }
}
{
  "headers": [
    "id",
    "month",
    "amount"
  ],
  "rows": [
    [
      "001",
      "Jan",
      "1.00"
    ],
    [
      "1",
      "Feb",
      "null"
    ],
    [
      "002",
      "Jan",
      "0"
    ],
    [
      "002",
      "Feb",
      null
    ],
    [
      "003",
      "Jan",
      " "
    ],
    [
      "003",
      "Feb",
      "=1+1"
    ]
  ]
}

仅移除 001 的空 Feb 与 1 的空 Jan。002 中不存在的 Feb 值仍保留为 null;空白和文本 null 也保留。这个显式选项不会悄悄抹去缺失观测。

区分空列键与缺失列键

{
  "input": "id,month,value\nA,,1\nA\nB,Jan,2",
  "parseOptions": {
    "delimiter": ",",
    "header": true
  },
  "options": {
    "mode": "pivot",
    "rowKeys": [
      "id"
    ],
    "columnKey": "month",
    "valueColumns": [
      "value"
    ],
    "aggregation": "sum"
  }
}
{
  "headers": [
    "id",
    "pivot:[\"\",\"value\",\"sum\"]",
    "pivot:[null,\"value\",\"sum\"]",
    "pivot:[\"Jan\",\"value\",\"sum\"]"
  ],
  "rows": [
    [
      "A",
      "1",
      null,
      null
    ],
    [
      "B",
      null,
      null,
      "2"
    ]
  ]
}

空的 month 字符串与不存在的 month 字段生成不同的透视列。A 的空分类合计为 1,而缺失分类的记录没有数值,因此该聚合为 null。B 只有 Jan。元数据以原样字符串或 null 记录各分类。

为与行键重名的生成表头消除冲突

{
  "input": "\"pivot:[\"\"Jan\"\",\"\"amount\"\",\"\"sum\"\"]\",month,amount\n001,Jan,2",
  "parseOptions": {
    "delimiter": ",",
    "header": true
  },
  "options": {
    "mode": "pivot",
    "rowKeys": [
      "pivot:[\"Jan\",\"amount\",\"sum\"]"
    ],
    "columnKey": "month",
    "valueColumns": [
      "amount"
    ],
    "aggregation": "sum"
  }
}
{
  "headers": [
    "pivot:[\"Jan\",\"amount\",\"sum\"]",
    "pivot:[\"Jan\",\"amount\",\"sum\"] [2]"
  ],
  "rows": [
    [
      "001",
      "2"
    ]
  ]
}

原始行键表头本身就是 pivot:["Jan","amount","sum"],它保持不变;生成的聚合表头增加后缀 " [2]"。JSON 的 columns 元数据仍提供权威的源列、分类值和聚合方式映射。

透视无表头的分号分隔数据

{
  "input": "001;Jan;0.1\n001;Jan;0.2",
  "parseOptions": {
    "delimiter": ";",
    "header": false
  },
  "options": {
    "mode": "pivot",
    "rowKeys": [
      "column1"
    ],
    "columnKey": "column2",
    "valueColumns": [
      "column3"
    ],
    "aggregation": "sum"
  }
}
{
  "headers": [
    "column1",
    "pivot:[\"Jan\",\"column3\",\"sum\"]"
  ],
  "rows": [
    [
      "001",
      "0.3"
    ]
  ]
}

header:false 表示首行是数据,位置列名为 column1、column2 和 column3。编号 001、月份 Jan 的两行合计为 0.3。分隔符通过设置明确指定,不猜测文件格式。

透视与逆透视常见误区

  • 产品编号只在地区内唯一,却仅选择产品作为行键;应同时选择地区。
  • 把所选值列的非空计数误认为源行数或去重后的值数量。
  • 以为 001 与 1 是同一个键,或以为 CSV 能阻止电子表格自动推断类型。
  • 把标识符列用于数值聚合,或期待科学计数法与本地化数字分隔符能自动识别。
  • 把 1/3 等精确分数平均值误当成舍入小数,或直接当成另一次数值聚合可接受的十进制输入。
  • 尚未确认缺失观测在目标系统中的意义,就丢弃空值。
  • 以为聚合后的透视表可以无损恢复每条源记录。
  • 在电子表格中打开不可信的原始 CSV,或未检查隐私信息就分享结果。

限制与说明

  • 输入限制为 2 MiB 编码文件字节及 2 MiB 解码后 UTF-8 文本、10,000 条数据行、128 列,以及补齐缺失尾部字段后共 200,000 个单元格。输出限制为 50,000 行、含行键在内的 256 列、500,000 个单元格,JSON 与受公式防护的 CSV 各不得超过 12 MiB。不同的行键分组最多 10,000 个、列键分组最多 256 个;输出总列数可能先达到上限。在构造结果行之前,会检查行分组数 × 分类数 × 值列数带来的稠密增长。超限时阻止转换,不会静默截断。工作线程取消与请求超时用于限制执行,但不构成浏览器内存的硬隔离。
  • 键与逆透视标识符始终是原样字符串:001 与 1、A 与 a、空字符串与缺失的 null 各不相同。不会去空白、忽略大小写、转换数字或日期、规范化 Unicode、模糊匹配或执行公式。复合键按元组识别。行键、列键和值列的角色不能重叠。不选行键时,所有记录归入一个行分组;不选逆透视标识列时,仅输出变量名与值两列。透视行与分类按首次出现顺序排列,值列保留选择顺序。逆透视按输入行顺序及所选值列顺序输出,不自动排序。
  • 计数统计存在且非空的值,包括任意文本;它不是去重计数,也不是无条件统计源行数。数值聚合只跳过 null 与 "",要求完整字符串为可选负号、0 或非零开头的整数,后面可接小数点与小数数字。最多接受 100 个十进制数字和 50 位小数。空白、加号、科学计数法、分组分隔符、货币符号和前导零整数均被拒绝。BigInt 提供精确求和、最小值、最大值和平均值字符串,即使超过 JavaScript 安全整数范围也不会丢失精度。有限小数平均值使用规范化十进制字符串,循环小数平均值使用 1/3 等精确最简分数。十进制结果采用相同精度上限,分数的分子与分母分别限制为 100 位数字。小数末尾的零与负零会规范化;超出精度时整个转换失败。分数输出是字符串,不是后续数值聚合可接受的十进制输入。已有坐标但值全部为空时,计数为 "0",数值聚合为 null;输入中从未出现的坐标在任何聚合下均为 null。
  • 透视表头以 pivot: 开头,后接由分类值、值列名和聚合方式组成的 JSON 元组。若与所选行键表头冲突,会添加 " [2]" 等确定性后缀;JSON 列元数据保留精确映射。请勿按猜测的标点拆解名称。逆透视默认保留缺失的 null、现有的 "" 以及文本 "null"。丢弃空值只移除已存在的空字符串;缺失字段、空白与单词 null 仍保留。输出的变量名列和值列名称不能为空,必须彼此不同,且不得与保留的标识列重名。聚合、数值输出规范化及丢弃空字符串会损失信息,逆透视无法从聚合结果重建原交易明细。
  • 请明确选择逗号、分号、制表符或竖线,文件编码支持 UTF-8、UTF-16LE 或 UTF-16BE。编码无效或 BOM 不匹配时拒绝读取。表头不能为空,原样名称必须唯一;空白和大小写仍有意义。无表头时使用 column1、column2 等名称,由首条记录决定宽度。短行的缺失尾部值保留为 null;超宽记录或错误引号会被拒绝。每页预览 25 行、12 列,长名称和值会缩短;下载保留受限范围内的完整结果。JSON 保留结果字符串、null 和元数据,不保留原 CSV 字节。CSV 把 null 写为不带引号的空字段,把 "" 写为带引号的空字段,但普通读取器往往将二者合并。公式防护会添加英文单引号并改动风险表头/值;原始 CSV 可能触发公式,保存并重开后防护也未必有效。电子表格仍可能推断类型并改动编号。输入留在本地且不保存历史;下载可能暴露隐私,清空页面后文件仍会保留。

常见问题

同一个透视坐标出现多行时会怎样?

完整的行键元组、列键值和所选值列共同确定一个聚合单元格。请明确选择计数、求和、平均值、最小值或最大值。例如 0.1 与 0.2 的精确合计字符串为 0.3。工具不会悄悄保留首行或末行。若记录本应分别显示,请增加行键。

为什么金额被拒绝,或平均值显示为分数?

数值聚合采用严格格式,不会把带前导零的编号、含空白或加号的文本、科学计数法或超出支持精度的字符串猜成数字。请仅选择真正的数值列,或先清洗一份副本。(1 + 0 + 0) / 3 等平均值无法表示为有限小数,因此输出精确最简分数字符串 1/3,不会静默舍入。十进制结果及分数的组成部分均有明确精度上限。计数和逆透视可处理非数值文本,无需数值强制转换。

先透视再逆透视,能恢复原 CSV 吗?

通常不能。透视会合并重复坐标,可能规范化符合规则的数字写法,并为缺失组合创建单元格。逆透视可以把所选宽表单元格展开为长表,但无法恢复各笔交易、原始顺序或未保留的列。请保留原输入。JSON 保留的是转换结果的字符串、null 和列元数据,不是原文件的引号写法或字节。

空值、缺失值与文本 null 有什么不同?

已存在但长度为零的字段是空字符串;短记录末尾不存在的字段是缺失值;字符 null 只是普通文本。JSON 分别保留为 ""、null 与 "null"。逆透视默认保留三者;丢弃空值只移除已存在的零长度字符串,保留缺失的 null 字段。数值聚合跳过缺失值与空字符串,但把文本 null 判定为无效数字;计数则会统计这个非空文本。

相关工具