ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SQL Server 删除重复记录:用 TaoToken 统一 Key 跑通排查与清理脚本

SQL Server 删除重复记录:用 TaoToken 统一 Key 跑通排查与清理脚本 1. SQL Server 重复记录到底怎么识别为什么不能直接 DELETESQL Server 里处理重复记录最怕的不是写不出 DELETE而是删之前没搞清楚“什么算重复”。我见过太多人上来就DELETE FROM 表 WHERE 主字段 IN (SELECT 主字段 FROM 表 GROUP BY 主字段 HAVING COUNT(*) 1)结果把该保留的那条也一起删了整组数据全没了。所以第一步永远是识别不是删除。重复记录在 SQL Server 里通常分两种。第一种是完全重复所有字段的值一模一样这种多半是批量导入或同步任务重跑导致的。第二种是业务键重复比如订单号相同但创建时间不同或者手机号相同但姓名不一样。这两种的处理策略完全不同完全重复可以随便留一条业务键重复则要按规则决定留哪条。识别重复最直接的方式是分组计数。假设有一张dbo.CustomerOrder表业务上OrderNo应该唯一但实际出现了重复SELECT OrderNo, COUNT(*) AS Cnt FROM dbo.CustomerOrder GROUP BY OrderNo HAVING COUNT(*) 1 ORDER BY Cnt DESC;这条语句能快速告诉你哪些 OrderNo 重复了、各重复了几次。但它只给了聚合结果看不到具体是哪几行。要看到完整行就得用窗口函数SELECT *, ROW_NUMBER() OVER (PARTITION BY OrderNo ORDER BY CreatedAt ASC) AS rn FROM dbo.CustomerOrder WHERE OrderNo IN ( SELECT OrderNo FROM dbo.CustomerOrder GROUP BY OrderNo HAVING COUNT(*) 1 );ROW_NUMBER()按OrderNo分组再按CreatedAt升序编号。rn 1的就是每组里最早的那条rn 1的就是要清理的。这个思路比游标逐行删安全得多也比SELECT DISTINCT INTO #Tmp那种重建表的方式更可控因为它不会动表结构也不会因为临时表空间不足而中途失败。为什么不能直接 DELETE因为 SQL Server 的 DELETE 没有“每组保留一条”的语义。你写DELETE WHERE OrderNo IN (重复列表)它会把整组都删掉。必须借助 CTE 或子查询把“要删的行”精确定位出来才能只删多余的那部分。这也是后面 CTE 删除方案的核心。还有一个容易被忽略的点识别阶段一定要先跑 SELECT确认结果集符合预期再改成 DELETE。我习惯把 SELECT 和 DELETE 写成同一段 CTE先跑 SELECT 版本确认行数和内容没问题再把最外层改成 DELETE。这样出错概率最低。2. TaoToken 统一 Key 在 SQL 排查里的定位与准备写 SQL 排查脚本时经常需要让模型帮忙解释执行计划、改写查询、或者根据报错信息给出修复建议。如果每次都要在不同工具里切换、重新配 Key效率很低。TaoToken 在这里的角色就是一个统一的 API 通道你申请一个 Key就能在多种客户端里调用模型能力用来辅助生成和校验 SQL。它的官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。注意 API 地址不带 UTM 参数配置时直接用这个基础地址。准备阶段要做三件事。第一拿到 Key。登录后进入控制台在 API Keys 页面创建一个新 Key。建议按用途命名比如sql-server-dedup方便后面排查是哪个 Key 在调用。控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite API Keys 页面是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。第二确认你要用的模型 ID。不同客户端对模型名的写法可能略有差异但核心是 Base URL、Key、Model ID 三件套。如果你用的是 Claude Code 这类编码工具可以参考接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里的说明。Claude Code 的 Anthropic 兼容入口在 https://taotoken.net/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_contentClaudeCodeAnthropicutm_campaignrewrite 。第三想清楚你要模型帮你做什么。是让它根据表结构生成去重脚本还是把一段报错贴进去让它解释目的不同提示词写法不同。我的习惯是把表结构、重复样本、期望保留规则三样东西一起给它让它输出可执行的 T-SQL并且要求它标注哪些地方需要我根据实际列名替换。这里要强调一点TaoToken 是辅助生成和校验 SQL 的通道不是替代你执行 SQL 的工具。真正的 DELETE 操作还是在 SSMS 或 sqlcmd 里跑模型给的建议必须经过你人工确认。尤其是删除类语句永远先在测试库验证。如果你需要长期做数据库相关的编码和脚本维护可以考虑 Coding Plan入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。它适合那种需要反复调用模型、持续产出脚本的场景。如果只是偶尔验证一下模型输出用模型对话页面就够了https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 。3. 可复制的去重配置与 CTE 删除脚本这一节给出一套可以直接复制、按实际表名替换后使用的脚本。核心结构是先用 CTE 算出每组的行号再删除行号大于 1 的记录。整个过程在一个事务里完成方便回滚。先看识别部分。假设表是dbo.CustomerOrder业务键是OrderNo保留规则是“保留 CreatedAt 最早的那条如果 CreatedAt 相同则保留 Id 最小的”WITH DupRanked AS ( SELECT Id, OrderNo, CreatedAt, ROW_NUMBER() OVER ( PARTITION BY OrderNo ORDER BY CreatedAt ASC, Id ASC ) AS rn FROM dbo.CustomerOrder ) SELECT * FROM DupRanked WHERE rn 1 ORDER BY OrderNo, rn;先跑这条 SELECT看看要删的行是不是符合预期。确认无误后把最外层改成 DELETEBEGIN TRANSACTION; WITH DupRanked AS ( SELECT Id, ROW_NUMBER() OVER ( PARTITION BY OrderNo ORDER BY CreatedAt ASC, Id ASC ) AS rn FROM dbo.CustomerOrder ) DELETE FROM DupRanked WHERE rn 1; -- 先查一下影响行数 SELECT ROWCOUNT AS DeletedRows; -- 确认没问题再提交有问题就 ROLLBACK -- COMMIT TRANSACTION; -- ROLLBACK TRANSACTION;注意这里 DELETE 的目标是 CTE 本身不是原表。SQL Server 支持对可更新 CTE 执行 DELETE它会作用到基表上。这是 CTE 删除方案最简洁的写法。如果你需要保留的是“最新的一条”把 ORDER BY 改成CreatedAt DESC即可。如果业务键是多个字段比如OrderNo ProductIdPARTITION BY 里写两个字段就行PARTITION BY OrderNo, ProductId对于完全重复的记录所有字段都一样可以用另一种写法直接按所有列分组WITH FullyDup AS ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY Col1, Col2, Col3, Col4 ORDER BY (SELECT NULL) ) AS rn FROM dbo.CustomerOrder ) DELETE FROM FullyDup WHERE rn 1;这里ORDER BY (SELECT NULL)表示不关心顺序随便留一条。但实际生产中我不推荐这种写法因为“随便留一条”在审计上说不清楚。更好的做法是加一个自增 Id 或 CreatedAt 作为排序依据。如果你用的是 Cline MCP 或类似工具来辅助生成脚本配置时同样需要 Base URL、Key、Model ID 三件套。Base URL 填https://taotoken.net/apiKey 填你创建的那个Model ID 按文档里支持的写。这样模型生成的 SQL 可以直接贴到 SSMS 里跑。4. 验证请求与执行前后行数对比删除脚本跑完不能只看“命令已成功完成”。必须做行数对比确认删掉的数量和预期一致。执行前先记录总行数和重复组数SELECT COUNT(*) AS TotalBefore FROM dbo.CustomerOrder; SELECT COUNT(*) AS DupGroups FROM ( SELECT OrderNo FROM dbo.CustomerOrder GROUP BY OrderNo HAVING COUNT(*) 1 ) t;执行后再查一次SELECT COUNT(*) AS TotalAfter FROM dbo.CustomerOrder;理论上TotalBefore - TotalAfter应该等于“所有重复组的多余行数之和”。你可以用这条语句算出预期删除数SELECT SUM(Cnt - 1) AS ExpectedDeleted FROM ( SELECT OrderNo, COUNT(*) AS Cnt FROM dbo.CustomerOrder GROUP BY OrderNo HAVING COUNT(*) 1 ) t;如果实际删除数和 ExpectedDeleted 不一致说明要么脚本逻辑有问题要么在识别和执行之间数据发生了变化。这时候不要急着 COMMIT先 ROLLBACK 再排查。还有一个验证动作是检查是否还有重复SELECT OrderNo, COUNT(*) AS Cnt FROM dbo.CustomerOrder GROUP BY OrderNo HAVING COUNT(*) 1;这条语句返回空结果集才说明去重干净了。如果还有重复可能是 PARTITION BY 的字段选错了或者排序规则导致 rn 分配不符合预期。我试过在测试库跑完这套流程后把执行前后的行数、删除数、剩余重复数记在一个小表里方便回溯。这个习惯在多人协作的环境里特别有用别人一看就知道你做了什么。如果你想让模型帮你校验这段验证 SQL 写得对不对可以把表结构和验证语句贴到模型对话里让它检查是否有遗漏。模型对话入口https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 。5. 常见报错排查401、local proxy failed、reading choices、OAuth这一节对照几个真实会遇到的报错给出排查方向。401 Unauthorized这个最常见基本就是 Key 不对或没带上。检查三件事Key 是否复制完整有没有多余空格、请求头里是否带了Authorization: Bearer 你的Key、Base URL 是否写成了https://taotoken.net/api而不是别的地址。如果你在 Cline MCP 或 Claude Code 里配置确认 Base URL、Key、Model ID 三件套都填了缺一个都可能报 401。local proxy failed这个报错通常出现在客户端配置了本地代理但代理没启动或者代理地址写错。排查方法是先确认你的网络环境是否需要代理如果不需要就把客户端里的代理设置关掉。如果需要确认代理进程在运行、端口对得上。注意不要用任何违规的网络工具这里说的只是本地开发环境的常规代理配置。reading choices 相关报错这类报错一般出现在调用模型接口后解析响应时提示读取choices字段失败。原因可能是返回体不是预期的 JSON 结构比如返回了 HTML 错误页。排查时先把原始响应打印出来看确认是不是 401 或 404 导致的。如果是 404检查 API 路径是否拼错比如多加了斜杠或少写了版本段。OAuth 相关报错如果你用的是 Claude Code 这类带 OAuth 流程的工具报 OAuth 错误时先确认你走的是 Anthropic 兼容入口地址是 https://taotoken.net/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_contentClaudeCodeAnthropicutm_campaignrewrite 。OAuth 流程对回调地址和客户端配置比较敏感建议按接入文档一步步来不要跳步。文档入口https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。还有一个容易踩的坑在 Codex 的auth.json里配置时字段名和层级要对。如果你不确定格式先备份原文件再按文档里的示例改。改完跑一个最简单的请求验证不要一上来就跑复杂任务。排查顺序建议先确认 Key 和 Base URL再确认模型 ID最后看网络和客户端配置。大部分问题出在前两步。6. 把去重脚本沉淀成可复用流程去重这件事做完一次不算完关键是能不能沉淀成下次直接用的流程。我的做法是建一个DBA_Scripts库把识别、删除、验证三段 SQL 存成存储过程参数化表名和业务键字段。这样下次遇到类似问题改两个参数就能跑。存储过程的大致结构CREATE OR ALTER PROCEDURE dbo.usp_DedupByKey TableName SYSNAME, KeyColumns NVARCHAR(500), OrderColumn SYSNAME, DryRun BIT 1 AS BEGIN SET NOCOUNT ON; -- 动态拼 SQL先 SELECT 再决定是否 DELETE -- DryRun 1 时只返回要删的行 END;DryRun参数很关键默认 1 表示只查看不删除确认后再传 0 执行。这样能避免误操作。另外去重之后建议加唯一约束或唯一索引从根上防止再次出现重复。加索引前先确认数据已经干净否则会创建失败ALTER TABLE dbo.CustomerOrder ADD CONSTRAINT UQ_CustomerOrder_OrderNo UNIQUE (OrderNo);如果业务上允许软删除也可以考虑用过滤索引只对未删除的记录做唯一约束。最后把整个流程写成文档包括识别 SQL、删除 SQL、验证 SQL、回滚方案、以及用 TaoToken 辅助生成脚本时的提示词模板。这样团队里任何人遇到重复记录问题都能按文档走一遍不用从头摸索。需要长期维护这类脚本的话Coding Plan 入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 适合持续产出和迭代 SQL 脚本的场景。
返回列表