如何用C#从Select查询提取列名?含CONCAT字段处理需求
解决SQL查询中排除指定列时的复杂字段提取问题
你的核心问题是直接用逗号分割字段列表时,会被CONCAT这类带括号的表达式内部的逗号干扰,导致字段拆分错误。要解决这个问题,需要正确识别带嵌套括号的完整字段边界,而不是简单按逗号分割。
修正后的代码实现
using System; using System.Text.RegularExpressions; using System.Linq; public class Program { public static void Main() { string query = @" select c.id,person_id,c.customer_no,c.status,p.first_name,p.last_name, p.dob as DateOfBirth,concat(p.first_name,' ',p.last_name) as fullName from customer c inner join person p on p.id=c.person_id"; // 清理换行、制表符等连续空白字符 query = Regex.Replace(query, @"\s+", " ").Trim(); // 定位select和from的位置,提取字段区间 int selectIndex = query.IndexOf("select ", StringComparison.OrdinalIgnoreCase); int fromIndex = query.LastIndexOf(" from ", StringComparison.OrdinalIgnoreCase); if (selectIndex == -1 || fromIndex == -1) { Console.WriteLine("无效的SQL查询"); return; } string fieldSection = query.Substring(selectIndex + 7, fromIndex - (selectIndex + 7)).Trim(); // 正则匹配完整字段:处理嵌套括号,跳过表达式内部的逗号 string fieldPattern = @"((?:[^(),]+|\((?>[^()]+|\((?<depth>)|\)(?<-depth>))*\))+)(?:\s+as\s+(\w+))?"; var matches = Regex.Matches(fieldSection, fieldPattern, RegexOptions.IgnoreCase); string[] ignoredFields = new string[] { "id", "person_id", "DateOfBirth" }; var validFields = new System.Collections.Generic.List<string>(); foreach (Match match in matches) { string fullFieldExpr = match.Groups[1].Value.Trim(); // 优先取as指定的别名,无别名则提取字段名(处理带表前缀的情况) string fieldAlias = match.Groups[2].Success ? match.Groups[2].Value.Trim() : fullFieldExpr.Contains('.') ? fullFieldExpr.Split('.')[1].Trim() : fullFieldExpr.Trim(); if (!ignoredFields.Contains(fieldAlias, StringComparer.OrdinalIgnoreCase)) { // 保留原始字段表达式和别名(如果有) validFields.Add(fullFieldExpr + (match.Groups[2].Success ? " as " + fieldAlias : "")); } } string resultFields = string.Join(", ", validFields); string customQuery = $"select {resultFields} from ({query}) trimmed"; Console.WriteLine(customQuery); } }
关键说明
- 正则平衡组:
(?<depth>)和(?<-depth>)用来跟踪括号嵌套深度,确保不会把CONCAT内部的逗号误判为字段分隔符,完整提取带复杂表达式的字段。 - 别名处理逻辑:优先用
as指定的别名作为排除依据,无别名时自动提取字段名(兼容c.id这类带表前缀的写法)。 - 空白清理:用
\s+替换所有连续空白,避免换行、制表符干扰字段匹配。
运行后会正确保留concat(p.first_name,' ',p.last_name) as fullName这类复杂字段,同时排除指定的列。
内容的提问来源于stack exchange,提问作者Prasanna Kumar J
相关产品推荐
相关产品推荐

