You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用C#或SQL合并无共同关联字段且文件名大小写不一致的多份CSV数据表

如何用C#或SQL合并无共同关联字段且文件名大小写不一致的多份CSV数据表

看起来你是要把没有直接关联字段的CSV文件按Issue与对应CSV文件的逻辑绑定来合并,还要处理文件名大小写不统一的问题,我分别给你说下C#和SQL的具体实现思路和代码示例吧~


一、C# 实现方案

我这里用System.Data结合CsvHelper(NuGet包)来处理,既方便读取CSV,也能灵活处理数据合并:

步骤说明

  1. 处理文件名大小写问题:匹配文件时用StringComparison.OrdinalIgnoreCase忽略大小写;
  2. 建立Issue与对应CSV的映射关系:根据文件名和Issue名称的对应逻辑(比如validation_missing_head_tag.csv对应「Validation: Missing Tag」);
  3. 读取所有CSV数据:把overview和两个验证CSV的数据都读进内存;
  4. 按逻辑合并数据:将每个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与对应表的绑定)来合并数据:

步骤说明

  1. 准备数据库表:创建和CSV结构对应的表;
  2. 导入CSV数据:用BULK INSERT导入,Windows文件系统默认忽略大小写,所以不用特意处理文件名;
  3. 合并数据:通过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来处理~

火山引擎 最新活动