如何用C#或SQL合并无共同关联字段且文件名大小写不一致的多份CSV数据表
如何用C#或SQL合并无共同关联字段且文件名大小写不一致的多份CSV数据表
看起来你是要把没有直接关联字段的CSV文件按Issue与对应CSV文件的逻辑绑定来合并,还要处理文件名大小写不统一的问题,我分别给你说下C#和SQL的具体实现思路和代码示例吧~
一、C# 实现方案
我这里用System.Data结合CsvHelper(NuGet包)来处理,既方便读取CSV,也能灵活处理数据合并:
步骤说明
- 处理文件名大小写问题:匹配文件时用
StringComparison.OrdinalIgnoreCase忽略大小写; - 建立Issue与对应CSV的映射关系:根据文件名和Issue名称的对应逻辑(比如
validation_missing_head_tag.csv对应「Validation: Missing Tag」); - 读取所有CSV数据:把overview和两个验证CSV的数据都读进内存;
- 按逻辑合并数据:将每个Issue的信息,和对应CSV里的每一行做组合(相当于逻辑上的交叉连接)。
代码示例
using System; using System.Data; using System.IO; using System.Linq; using CsvHelper; using System.Globalization; class CsvMerger { static void Main(string[] args) { string basePath = @"C:\Report\"; // 1. 读取overview.csv的Issue数据 DataTable overviewTable = ReadCsvToDataTable(Path.Combine(basePath, "overview.csv")); // 2. 建立Issue名称和对应CSV文件名的映射(忽略大小写) var issueToCsvMap = new (string IssueName, string CsvFileName)[] { ("Validation: Missing <head> Tag", "validation_missing_head_tag.csv"), ("Validation: Multiple <body> Tags", "validation_multiple_body_tags.csv") }; // 3. 准备最终结果表 DataTable resultTable = CreateResultTable(); // 4. 遍历每个Issue,合并对应CSV的数据 foreach (var map in issueToCsvMap) { // 忽略大小写找对应CSV文件 string csvPath = Directory.GetFiles(basePath, map.CsvFileName, SearchOption.TopDirectoryOnly) .FirstOrDefault(f => string.Equals(Path.GetFileName(f), map.CsvFileName, StringComparison.OrdinalIgnoreCase)); if (string.IsNullOrEmpty(csvPath)) { Console.WriteLine($"未找到目标文件: {map.CsvFileName}"); continue; } DataTable detailTable = ReadCsvToDataTable(csvPath); // 找到当前Issue在overview中的行 DataRow[] issueRows = overviewTable.Select($"[Issue Name] = '{map.IssueName.Replace("'", "''")}'"); if (issueRows.Length == 0) continue; DataRow issueRow = issueRows[0]; // 把Issue信息和每个detail行合并 foreach (DataRow detailRow in detailTable.Rows) { DataRow newRow = resultTable.NewRow(); // 复制Issue列 newRow["Issue Name"] = issueRow["Issue Name"]; newRow["Issue Type"] = issueRow["Issue Type"]; newRow["Issue Priority"] = issueRow["Issue Priority"]; // 复制CSV详情列 newRow["Address"] = detailRow["Address"]; newRow["Content Type"] = detailRow["Content Type"]; newRow["Status Code"] = detailRow["Status Code"]; newRow["Status"] = detailRow["Status"]; newRow["Indexability"] = detailRow["Indexability"]; resultTable.Rows.Add(newRow); } } // 5. 导出结果到新CSV WriteDataTableToCsv(resultTable, Path.Combine(basePath, "merged_result.csv")); Console.WriteLine("合并完成,结果已保存到 merged_result.csv"); } // 读取CSV到DataTable private static DataTable ReadCsvToDataTable(string filePath) { using var reader = new StreamReader(filePath); using var csv = new CsvReader(reader, CultureInfo.InvariantCulture); using var dr = new CsvDataReader(csv); var dt = new DataTable(); dt.Load(dr); return dt; } // 创建结果表的结构 private static DataTable CreateResultTable() { var dt = new DataTable(); dt.Columns.Add("Issue Name"); dt.Columns.Add("Issue Type"); dt.Columns.Add("Issue Priority"); dt.Columns.Add("Address"); dt.Columns.Add("Content Type"); dt.Columns.Add("Status Code"); dt.Columns.Add("Status"); dt.Columns.Add("Indexability"); return dt; } // 把DataTable导出为CSV private static void WriteDataTableToCsv(DataTable dt, string filePath) { using var writer = new StreamWriter(filePath); using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); // 写表头 foreach (DataColumn col in dt.Columns) { csv.WriteField(col.ColumnName); } csv.NextRecord(); // 写数据行 foreach (DataRow row in dt.Rows) { foreach (var item in row.ItemArray) { csv.WriteField(item); } csv.NextRecord(); } } }
注意点
- 记得先通过NuGet安装
CsvHelper包; - 如果你的Issue和CSV的对应关系有规律(比如文件名里的关键词和Issue名称对应),可以不用硬编码映射,而是通过字符串匹配自动生成(比如从Issue名称提取关键词,忽略大小写匹配文件名)。
二、SQL 实现方案
这里以SQL Server为例,思路是先把CSV导入到数据库表,再通过逻辑关联(Issue与对应表的绑定)来合并数据:
步骤说明
- 准备数据库表:创建和CSV结构对应的表;
- 导入CSV数据:用
BULK INSERT导入,Windows文件系统默认忽略大小写,所以不用特意处理文件名; - 合并数据:通过
CROSS JOIN把Issue行和对应表的行合并,再用UNION ALL把两部分结果拼接起来。
代码示例
1. 创建表结构
-- 创建overview表 CREATE TABLE dbo.overview ( [Issue Name] VARCHAR(255), [Issue Type] VARCHAR(50), [Issue Priority] VARCHAR(50) ); -- 创建验证表1 CREATE TABLE dbo.validation_missing_head_tag ( [Address] VARCHAR(255), [Content Type] VARCHAR(50), [Status Code] INT, [Status] VARCHAR(50), [Indexability] VARCHAR(50) ); -- 创建验证表2 CREATE TABLE dbo.validation_multiple_body_tags ( [Address] VARCHAR(255), [Content Type] VARCHAR(50), [Status Code] INT, [Status] VARCHAR(50), [Indexability] VARCHAR(50) );
2. 导入CSV数据
-- 导入overview.csv(注意文件路径用单引号转义,或者用双反斜杠) BULK INSERT dbo.overview FROM 'C:\Report\overview.csv' WITH ( FIRSTROW = 2, -- 跳过表头 FIELDTERMINATOR = ',', -- 字段分隔符 ROWTERMINATOR = '\n', -- 行分隔符 CODEPAGE = '65001' -- UTF-8编码,如果是GBK用936 ); -- 导入validation_missing_head_tag.csv(Windows会自动忽略文件名大小写匹配) BULK INSERT dbo.validation_missing_head_tag FROM 'C:\Report\validation_missing_head_tag.csv' WITH ( FIRSTROW = 2, FIELDTERMINATOR = ',', ROWTERMINATOR = '\n', CODEPAGE = '65001' ); -- 导入validation_multiple_body_tags.csv BULK INSERT dbo.validation_multiple_body_tags FROM 'C:\Report\validation_multiple_body_tags.csv' WITH ( FIRSTROW = 2, FIELDTERMINATOR = ',', ROWTERMINATOR = '\n', CODEPAGE = '65001' );
3. 合并数据查询
SELECT o.[Issue Name], o.[Issue Type], o.[Issue Priority], v.[Address], v.[Content Type], v.[Status Code], v.[Status], v.[Indexability] FROM dbo.overview o CROSS JOIN dbo.validation_missing_head_tag v WHERE o.[Issue Name] = 'Validation: Missing <head> Tag' UNION ALL SELECT o.[Issue Name], o.[Issue Type], o.[Issue Priority], v.[Address], v.[Content Type], v.[Status Code], v.[Status], v.[Indexability] FROM dbo.overview o CROSS JOIN dbo.validation_multiple_body_tags v WHERE o.[Issue Name] = 'Validation: Multiple <body> Tags' ORDER BY o.[Issue Name];
注意点
- 如果你的CSV里有带逗号的字段(比如
Address里的空格加逗号),BULK INSERT可能会解析错误,这时候建议用带文本限定符的格式,或者用SSIS导入更稳妥; - 如果是MySQL等其他数据库,导入方式会有差异(比如
LOAD DATA INFILE),但合并数据的逻辑是一样的,都是用交叉连接加UNION。
如果你的Issue和CSV的对应关系更复杂,或者有更多文件,也可以根据这个思路扩展,比如C#里自动扫描文件名生成映射,SQL里用动态SQL来处理~




