【问题标题】:How to find all select queries from a storedprocedure script in C#如何从 C# 中的存储过程脚本中查找所有选择查询
【发布时间】:2015-01-22 07:19:43
【问题描述】:

我的 SQL 服务器中有一个过程列表,我想用该表的 select(所有列名)替换所有 select * 语句。为此,我需要识别程序脚本的所有选择语句。这是我当前的代码。

  foreach (StoredProcedure myproc in SelectedProcedures)
                {


                    StringBuilder builder = new StringBuilder();
                    ScriptingOptions scriptOptions = new ScriptingOptions();
                    StringCollection tableScripts = myproc.Script();
                    foreach (string script in tableScripts)
                    {
                        if (script.ToUpper().Contains("CREATE PROCEDURE"))
                        {
                          string x = script.ToUpper().Replace("CREATE PROCEDURE", "ALTER PROCEDURE");
                            builder.Append(x + "\n");
                            if (script.ToString().ToUpper().Replace("  ", " ").Contains("SELECT * FROM "))
                            {
                                string u = script.ToString().ToUpper().Replace("  ", " ");
                                List<string> values = u.Split(new string[] { "SELECT * FROM " }, StringSplitOptions.RemoveEmptyEntries).ToList();
                                List<string> tablenames = new List<string>();
                                values.RemoveAt(0);
                                foreach (string t in values)
                                {
                                    if (!t.Trim().StartsWith("#") && !t.Trim().StartsWith("@"))
                                    {
                                        tablenames.Add(t.Split(' ')[0].Replace("[", "").Replace("]", "").ToUpper().Trim());
                                    }
                                }
                                tablenames.OrderBy(xx => xx);
                                List<Table> tables = SourceDB.Tables.Cast<Table>().Where(t => tablenames.Contains(t.ToString().Replace("[", "").Replace("]", "").ToUpper())).Select(t => t).ToList();

                                foreach (var t in tablenames)
                                {
                                    try
                                    {
                                        Table mytable = SourceDB.Tables[t.Split('.')[1], t.Split('.')[0]];
                                        if (mytable != null)
                                        {
                                            StringBuilder builder1 = new StringBuilder();
                                            builder1.Append("SELECT ");

                                            foreach (Column column in mytable.Columns)
                                            {
                                                builder1.Append("[" + column.Name.ToUpper() + "], ");
                                            }
                                            builder1.Remove(builder1.ToString().LastIndexOf(", "), 1);
                                            builder1.Append(" from ");
                                            builder1.Append(mytable.ToString());
                                            GeneratedScripts["Procedures"].Add(builder1);
                                            string k = builder.ToString().ToUpper();
                                            string n = k.Replace("  ", " ").Replace("SELECT * FROM " + mytable.ToString().ToUpper(), builder1.ToString());
                                            n = n.Replace("  ", " ").Replace("SELECT * FROM " + t, builder1.ToString());
                                            builder = new StringBuilder(n);

                                        }
                                    }
                                    catch (Exception)
                                    {

                                        continue;
                                    }



                                }

                            }
                        }



                    }

但是,这省略了 select B.* from table A inner join table B 之类的情况 我可以使用额外的逻辑,如 Regex 来处理这些事情,但我想要一种更合适的方式,以便在字符串列表中检索过程脚本的所有选择查询,然后我可以在所有查询中使用我的自定义逻辑一个接一个。

谢谢

【问题讨论】:

  • 为了正确执行此操作,您必须编写一个完整的 SQL 解析器——这不是一件容易的事。你可能想看看做这种事情的商业产品。
  • 有一个现有的免费 Api,看看 DacFx 和 TSqlObject,它们将为您提供存储过程中的语句。 qxg 在他的回答中显示的是 ssdt 使用的 api(如果你确实写了它,请 Oss 它,因为它对其他人有用)。
  • 它实际上是 ScriptDom 而不是 TSqlObjects,这显示了如何获取语句,但您也可以获取列和表等:blogs.msdn.com/b/arvindsh/archive/2013/04/04/…

标签: c# sql-server smo


【解决方案1】:

如果你的数据库是SSDT开发的就很简单,Visual Studio 2013之后默认包含SSDT。在SSDT中,右键项目节点,选择Refactor -> Expand Wildcards。 SSDT 内部构建了数据库模式的模型,因此计算准确的列非常聪明。

有了这个工具(我相信其他工具),你仍然需要注意像EXISTS (SELECT * FROMSELECT COUNT(*)这样的查询。更换它们没有多大意义。

【讨论】:

    【解决方案2】:

    我会做一些假设:

    查找 SELECT 和 FROM 之间出现 * 的正则表达式匹配。 唯一可能的排除是,如果 SELECT 前面紧跟一个 'EXISTS(',它可能包含也可能不包含空格或制表符。

    其他替代方法是只关注执行计划缓存并查找您最常用的查询。

    另一个很好的(或更好的)替代方法是开始进行代码分析,其中可能包含相关规则。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-08
      • 2013-03-12
      • 1970-01-01
      • 1970-01-01
      • 2020-09-15
      • 1970-01-01
      相关资源
      最近更新 更多