dsh-pivot-join
v0.1.0
Published
Table pipeline toolkit for DeepSeek Harness: join two CSV/JSON tables (inner/left/right/outer), build pivot tables, and run group-by aggregations with readable aligned output. Zero runtime dependencies, read-only.
Maintainers
Readme
dsh-pivot-join
DeepSeek Harness 的表格流水线工具:join_tables 按连接键合并两张表,pivot_table 把行转成透视表,group_aggregate 做分组统计。支持 CSV / JSON / JSONL 输入,输出对齐易读的表格。只读、零运行时依赖。
- 源码:https://github.com/geeklei/dsh-plugins/tree/main/dsh-pivot-join
- npm:https://www.npmjs.com/package/dsh-pivot-join
功能说明
对话里拿到的数据常是几张独立的 CSV:一张订单、一张客户、一张销量。要回答问题,往往先得把表拼起来、把行转成列、分组求和——这三个动作在终端里靠肉眼做非常费劲。本插件把它们变成三个工具。
join_tables —— 把两张表按连接键拼起来
支持 inner(交集)、left(保留左表全部)、right、outer(全外连接)四种方式,并给出匹配统计,能立刻看出「有多少行没有对上」:
来源:orders.csv × customers.csv
连接方式:inner,连接键:cust_id=id
左表:4 行 × 3 列;右表:3 行 × 3 列
结果:3 行 × 6 列(匹配 3,左未匹配 1,右未匹配 1)
| order_id | cust_id | amount | id | name | city |
| -------- | ------- | ------ | --- | ----- | ---- |
| 1001 | 1 | 120 | 1 | alice | 深圳 |
| 1002 | 2 | 80 | 2 | bob | 北京 |
| 1003 | 1 | 60 | 1 | alice | 深圳 |连接键可以是同名列(on="id")、不同名列(on="cust_id=id"),也可以是多列(on="region,quarter")。两侧同名的连接键只会保留一份,避免出现重复列。
pivot_table —— 把行转成列(透视表)
指定行维度、透视列、值列和聚合方式,直接得到一张交叉表:
来源:sales.csv
透视:index=region,columns=quarter,values=amount,agg=sum
源数据:6 行 × 5 列;分组 3 个,透视列取值 2 个
| region | Q1 | Q2 | 合计 |
| ------ | --- | --- | ---- |
| 华北 | 90 | 60 | 150 |
| 华东 | 200 | 150 | 350 |
| 华南 | 0 | 200 | 200 |透视列的去重取值自动成为新列名,并附一列「合计」。不写 values 时按行数计数。
group_aggregate —— 分组统计
一条 aggs 清单可以同时算多个指标,amount:sum,qty:avg,count 表示「金额求和 + 数量求均值 + 行数」:
来源:sales.csv
分组:region;聚合:amount→sum, qty→avg, 行→count;排序:-value
源数据:6 行 × 5 列;分组数 3
| region | amount_sum | qty_avg | count |
| ------ | ---------- | ------- | ----- |
| 华东 | 350 | 3 | 3 |
| 华南 | 200 | 5 | 1 |
| 华北 | 150 | 1.5 | 2 |结果默认按分组键升序,sort=-value 可按首个聚合值降序(上例即按金额从高到低)。
三种输入格式都会被自动识别:CSV(逗号 / 制表符 / 分号 / 竖线分隔均可)、JSON 对象数组、JSONL(每行一个对象)。CSV 还支持带引号的字段、字段内换行与双写引号转义。
安装
npm install dsh-pivot-join安装后在 cordis.patch.yml 中加入:
- insert:
- id: pivot-join
name: "dsh-pivot-join"使用说明
三个工具都支持 path(文件路径)或 text(内联文本)二选一,text 优先。CSV 字段默认去除首尾空白(trim 可关闭)。
join_tables
| 参数 | 类型 | 说明 |
|---|---|---|
| path_a / text_a | string | 左表(文件路径或内联文本) |
| path_b / text_b | string | 右表(文件路径或内联文本) |
| on | string | 连接键(必填):id 或 left_id=right_id;多键用逗号分隔 |
| how | string | inner | left(默认) | right | outer(full 等同 outer) |
| delimiter | string | CSV 分隔符,默认 auto 自动探测 |
| trim | boolean | 是否去除字段首尾空白,默认 true |
| limit | number | 结果预览行数,默认 20,上限 200 |
| max_chars | number | 输出字符上限,默认 20000,上限 200000 |
| max_rows | number | 单表读取行数上限,默认 100000,上限 1000000 |
| max_size | number | 文件大小上限(KB),默认 10240,上限 51200 |
用户:订单表和客户表按客户 ID 关联一下
join_tables(path_a="orders.csv", path_b="customers.csv", on="cust_id=id", how="inner")用户:看看哪些客户一单都没下
join_tables(path_a="customers.csv", path_b="orders.csv", on="id=cust_id", how="left")pivot_table
| 参数 | 类型 | 说明 |
|---|---|---|
| path / text | string | 数据源(文件路径或内联文本) |
| index | string | 行维度列,多列用逗号分隔,如 region,product |
| columns | string | 透视列(必填),其去重取值会成为新列名 |
| values | string | 被聚合的值列;留空则统计行数 |
| agg | string | sum(默认) | avg | min | max | count | first | last;无 values 时默认 count |
| delimiter / trim | — | 同 join_tables |
| limit | number | 结果预览行数,默认 20,上限 200 |
| max_chars / max_rows / max_size | number | 同上 |
用户:按区域和季度汇总一下销售额
pivot_table(path="sales.csv", index="region", columns="quarter", values="amount", agg="sum")用户:看看每个区域的订单笔数分布
pivot_table(path="sales.csv", index="region", columns="quarter")group_aggregate
| 参数 | 类型 | 说明 |
|---|---|---|
| path / text | string | 数据源(文件路径或内联文本) |
| group_by | string | 分组列,多列用逗号分隔;留空表示对全表汇总 |
| aggs | string | 聚合清单(必填),如 amount:sum,qty:avg,count |
| sort | string | key(默认,分组键升序) | -key | value | -value |
| delimiter / trim | — | 同 join_tables |
| limit | number | 结果预览行数,默认 20,上限 200 |
| max_chars / max_rows / max_size | number | 同上 |
aggs 写法:
列名:聚合—— 如amount:sum,结果列名为amount_sum裸 count或*:count—— 统计行数,结果列名为count列名:count—— 统计该列的非空值个数
用户:按区域统计金额合计、数量均值和记录条数
group_aggregate(path="sales.csv", group_by="region", aggs="amount:sum,qty:avg,count", sort="-value")用户:整张表一共多少条记录、金额合计多少
group_aggregate(path="sales.csv", aggs="amount:sum,count")典型场景
- 对账单核对:两张表
on="订单号"做outer连接,一次看出双方各自多出的记录。 - 补齐维度信息:订单表只有客户 ID,
left连接客户表拿到姓名与城市。 - 交叉分析:
pivot_table把「区域 × 季度」展成矩阵,趋势一眼可见。 - 指标汇总:
group_aggregate一条命令同时产出求和、均值、计数。 - 数据质量核查:连接后的「左未匹配 / 右未匹配」数字即脏数据规模。
- 全表盘点:
group_by留空即得到全表汇总行。 - JSON 接口数据:直接把接口返回的 JSON 数组或 JSONL 丢进来,无需先转 CSV。
- 口径抽查:
limit=5只看前几行,确认聚合口径无误后再放大。
安全边界
- 只读:三个工具都不写入、不修改、不删除文件;测试含源文件 size/mtime 不变的只读性断言。
- 不访问网络:全部处理在本地完成,无任何外部请求。
- 不执行输入:纯文本解析,不做
eval、不加载模块、不执行单元格内容。 - 二进制拒绝:读取时检测 NUL 字节,疑似二进制文件直接拒绝解析。
- 多层上限:文件大小上限 51200 KB、读取行数上限 1000000、输出字符上限 200000、结果预览上限 200 行、透视列取值上限 50 个。超限即拒绝或截断并显式提示。
- 不写临时文件:不落盘任何中间结果。
- 不脱敏:字段值原样输出。若表中含密钥等敏感信息,请先用
dsh-credential-scan检查再处理。
其他插件集成说明
| 协作插件 | 集成方式 |
|---|---|
| dsh-xml-toolkit | parse_xml(shape="json") 的结果可直接作为本插件的 JSON 输入 |
| dsh-json-yaml-toolkit | 接口报文先转换 / 校验,再交给本插件做连接与聚合 |
| dsh-csv-explorer | 先用 csv-explorer 预览列名与取值分布,确定连接键与透视列 |
| dsh-chart-ascii | 把本插件输出的表格交给 chart-ascii 画成终端柱状图 / 折线图 |
| dsh-file-search | 先定位工作区内相关 CSV 文件,再批量连接比对 |
| dsh-fs-inspector | 事先查看文件体量,据此设置合适的 max_size / max_rows |
| dsh-text-stats | 对原始字段做词频与体量统计,与结构化聚合互补 |
| dsh-credential-scan | 处理前扫描表内是否混入凭据、密钥 |
版本说明
- 0.1.0(2026-09-30):初始版本。
join_tables:inner / left / right / outer 四种连接;单列、多列与异名列名映射;同名键列自动去重;匹配 / 未匹配统计pivot_table:行维度 + 透视列 + 值列聚合,自动展开列并附加合计列;透视列取值上限 50group_aggregate:多指标聚合(sum/avg/min/max/count/first/last),支持按分组键或聚合值排序- 输入自动识别 CSV / JSON / JSONL;CSV 支持引号转义、字段内换行、CRLF、BOM 与 4 种分隔符探测
- 中日韩字符按显示宽度对齐输出;二进制拒绝与多层上限保护
RoadMap
v0.2(计划)
join_tables支持模糊键(去空格、忽略大小写、前缀匹配)与近似连接(按相似度找最接近的一行)pivot_table支持多值列与百分比 / 占比模式(行占比、列占比、总计占比)group_aggregate支持分位数(p50 / p90 / p99)与中位数- 输出格式选项:
format=markdown|tsv|csv,便于把结果直接写回文件
v0.3(展望)
filter_rows:按条件表达式筛选后再连接 / 透视union_tables:多表纵向合并并处理列不一致- 流式处理超大表(分块读取,突破整体载入内存的限制)
- 表达式列(
amount*qty:sum形式的计算指标)
FAQ
Q:on 里写多列是什么规则?
逗号分隔,每项可以是 列名(两侧同名)或 左列=右列。也可以混用,如 on="region,month=mon"。
Q:为什么同名连接键在结果里只有一份,异名的却有两份?
同名键两份完全重复,去掉更易读;异名键(如 cust_id=id)保留双方,便于在 outer 场景下看出该行来自哪一侧。这是刻意设计。
Q:left 连接后没匹配上的行,右侧字段是什么?
空字符串。可用 how=outer 同时看到右侧未匹配的行。
Q:透视表中某个格子显示 0 或空白,是什么意思?
该组在该透视列取值下没有数据。sum / count 显示 0,avg / min / max 显示空白(无数据可平均)。
Q:透视列取值太多怎么办?
默认最多保留 50 个(按值排序取前 50),超出部分会在结果上方给出提示。建议先筛掉噪音列,或用多列 index 分组。
Q:count 和行数有什么区别?
count(裸写或 *:count)统计行数;列名:count 统计该列非空值的个数。两者在有空值时会不同。
Q:数字列是怎么识别的?
渲染时若某列所有非空单元格都能转成数字,就按数值右对齐显示。聚合时无法转成数字的值会被忽略(count 除外)。
Q:中文列名、中文取值有问题吗? 没有。表头与取值都按 UTF-8 处理,输出会按显示宽度对齐中日韩字符。
Q:字段里本身带逗号怎么办?
用双引号包起来,例如 "深圳,南山";字段内的双引号写成两个双引号 "" 即可。
Q:能从 npm 的 lock 文件或 Excel 里直接读吗?
package-lock.json 这类 JSON 可以直接读;.xlsx 不行,需要先导出为 CSV 或 JSON。
源码与发布地址
- 源码:https://github.com/geeklei/dsh-plugins/tree/main/dsh-pivot-join
- npm:https://www.npmjs.com/package/dsh-pivot-join
许可证
MIT
