如何用C#生成含列名与列描述的SQL Server查询结果CSV文件
嘿,这个需求我之前帮不少ASP.NET开发者解决过,其实核心就是先手动生成包含列名和列描述的前两行,再把SQL查询出来的数据逐行追加进去就行!我给你完善代码示例,分两种场景来写,你可以按需选用:
场景1:固定列名和描述(适合查询结构不变的情况)
这种方式直接硬编码列名和对应的描述,简单直观:
protected void ExportCSV(object sender, EventArgs e) { // 读取连接字符串 string constr = ConfigurationManager.ConnectionStrings["YourConnectionString"].ConnectionString; // 你的SQL查询语句(注意列顺序要和下面的字典对应) string query = "SELECT Id, UserName, RegisterDate FROM dbo.Users"; // 定义列名与对应描述的映射 Dictionary<string, string> columnMeta = new Dictionary<string, string> { {"Id", "用户唯一标识ID"}, {"UserName", "用户登录账号"}, {"RegisterDate", "用户注册时间"} }; // 准备响应,让浏览器触发下载 Response.Clear(); Response.Buffer = true; Response.ContentType = "text/csv"; Response.AddHeader("Content-Disposition", "attachment;filename=UserExport.csv"); // 用UTF8带BOM,避免中文乱码 using (StreamWriter sw = new StreamWriter(Response.OutputStream, Encoding.UTF8)) { // 第一行:写入列名(加双引号避免列名含逗号) string headerLine = string.Join(",", columnMeta.Keys.Select(col => $"\"{col}\"")); sw.WriteLine(headerLine); // 第二行:写入列描述(和列名顺序一一对应) string descLine = string.Join(",", columnMeta.Values.Select(desc => $"\"{desc}\"")); sw.WriteLine(descLine); // 执行SQL查询,写入数据行 using (SqlConnection con = new SqlConnection(constr)) { using (SqlCommand cmd = new SqlCommand(query, con)) { con.Open(); using (SqlDataReader dr = cmd.ExecuteReader()) { while (dr.Read()) { List<string> rowValues = new List<string>(); foreach (string colName in columnMeta.Keys) { // 处理空值,转义内容里的双引号(CSV规范要求把"换成"") string value = dr[colName] != DBNull.Value ? dr[colName].ToString() : ""; rowValues.Add($"\"{value.Replace("\"", "\"\"")}\""); } sw.WriteLine(string.Join(",", rowValues)); } } } } sw.Flush(); Response.End(); } }
场景2:动态获取列描述(从SQL Server系统视图读取,适合动态查询)
如果你的查询表是动态的,或者想直接用SQL Server里给列设置的扩展属性描述(就是SSMS里列的Description属性),可以通过系统视图自动获取:
protected void ExportCSV(object sender, EventArgs e) { string constr = ConfigurationManager.ConnectionStrings["YourConnectionString"].ConnectionString; // 替换成你的目标表名(架构+表名) string targetTable = "dbo.Users"; // 查询该表的所有列(和系统视图列顺序一致) string query = $"SELECT * FROM {targetTable}"; // 从SQL Server系统视图获取列名和对应的描述 Dictionary<string, string> columnMeta = new Dictionary<string, string>(); using (SqlConnection con = new SqlConnection(constr)) { string descQuery = @" SELECT c.name AS ColumnName, ISNULL(ep.value, '无描述') AS ColumnDescription FROM sys.columns c LEFT JOIN sys.extended_properties ep ON c.object_id = ep.major_id AND c.column_id = ep.minor_id AND ep.name = 'MS_Description' WHERE c.object_id = OBJECT_ID(@TargetTable) ORDER BY c.column_id"; using (SqlCommand cmd = new SqlCommand(descQuery, con)) { cmd.Parameters.AddWithValue("@TargetTable", targetTable); con.Open(); using (SqlDataReader dr = cmd.ExecuteReader()) { while (dr.Read()) { columnMeta.Add(dr["ColumnName"].ToString(), dr["ColumnDescription"].ToString()); } } } } // 后续写入CSV的逻辑和场景1完全一致 Response.Clear(); Response.Buffer = true; Response.ContentType = "text/csv"; Response.AddHeader("Content-Disposition", "attachment;filename=DynamicExport.csv"); using (StreamWriter sw = new StreamWriter(Response.OutputStream, Encoding.UTF8)) { // 写入列名行 sw.WriteLine(string.Join(",", columnMeta.Keys.Select(col => $"\"{col}\""))); // 写入描述行 sw.WriteLine(string.Join(",", columnMeta.Values.Select(desc => $"\"{desc}\""))); // 写入数据行 using (SqlConnection con = new SqlConnection(constr)) { using (SqlCommand cmd = new SqlCommand(query, con)) { con.Open(); using (SqlDataReader dr = cmd.ExecuteReader()) { while (dr.Read()) { List<string> rowValues = new List<string>(); foreach (string colName in columnMeta.Keys) { string value = dr[colName] != DBNull.Value ? dr[colName].ToString() : ""; rowValues.Add($"\"{value.Replace("\"", "\"\"")}\""); } sw.WriteLine(string.Join(",", rowValues)); } } } } sw.Flush(); Response.End(); } }
关键注意点
- 所有写入CSV的内容都加了双引号,避免内容里的逗号、换行符破坏CSV格式
- 转义了内容中的双引号(把
"替换成""),符合CSV官方规范 - 用
Encoding.UTF8带BOM写入,避免中文在Excel中显示乱码 - 如果你的查询是自定义的多表联合查询,场景1的硬编码方式会更稳妥,确保列顺序完全匹配
内容的提问来源于stack exchange,提问作者sebyrock
相关产品推荐
相关产品推荐

