代码之家  ›  专栏  ›  技术社区  ›  user1228

将exec sp_executesql转换为普通查询的简单方法?

  •  32
  • user1228  · 技术社区  · 16 年前

    exec sp_executesql 
    N'/*some query here*/', 
    N'@someParameter tinyint',
    @ someParameter =2
    

    DECLARE @someParameter tinyint
    SET @someParameter = 2
    
    /*some query here*/
    

    11 回复  |  直到 16 年前
        1
  •  1
  •   Yvo    16 年前

    http://execsqlformat.herokuapp.com/

    样本输入:

    exec sp_executesql 
              N'SELECT * FROM AdventureWorks.HumanResources.Employee 
              WHERE ManagerID = @level',
              N'@level tinyint',
              @level = 109;
    

    BEGIN
    DECLARE @level tinyint;
    
    SET @level = 109;
    
    SELECT * FROM AdventureWorks.HumanResources.Employee  
              WHERE ManagerID = @level
    END
    

    http://sqlformat.appspot.com

        2
  •  35
  •   Jarrod Dixon IndianaJones    12 年前

    .NET Fiddle download LINQPad 5 file

    输入:

    exec sp_executesql N'UPDATE MyTable SET [Field1] = @0, [Field2] = @1',N'@0 nvarchar(max) ,@1 int',@0=N'String',@1=0
    

    UPDATE MyTable SET [Field1] = N'String', [Field2] = 0
    

    代码:

    using System;
    using System.Linq;
    using System.Text.RegularExpressions;
    
    public class Program
    {
        public static void Main()
        {
            var sql = @"exec sp_executesql N'UPDATE MyTable SET [Field1] = @0, [Field2] = @1',N'@0 nvarchar(max) ,@1 int',@0=N'String',@1=0";
            Console.WriteLine(ConvertSql(sql));
        }
    
        public static string ConvertSql(string origSql)
        {
            var re = new Regex(@"exec*\s*sp_executesql\s+N'([\s\S]*)',\s*N'(@[\s\S]*?)',\s*([\s\S]*)", RegexOptions.IgnoreCase); // 1: the sql, 2: the declare, 3: the setting
            var match = re.Match(origSql);
            if (match.Success)
            {
                var sql = match.Groups[1].Value.Replace("''", "'");
                //var declare = match.Groups[2].Value;
                var setting = match.Groups[3].Value + ',';
    
                // to deal with comma or single quote in variable values, we can use the variable name to split
                var re2 = new Regex(@"@[^',]*?\s*=");
                var variables = re2.Matches(setting).Cast<Match>().Select(m => m.Value).ToArray();
                var values = re2.Split(setting).Where(s=>!string.IsNullOrWhiteSpace(s)).Select(m => m.Trim(',').Trim().Trim(';')).ToArray();
    
                for (int i = variables.Length-1; i>=0; i--)
                {
                    sql = Regex.Replace(sql, "(" + variables[i].Replace("=", "")+")", values[i], RegexOptions.Singleline);
                }
                return sql;     
            }
    
            return @"Unknown sql query format.";
        }
    }
    
        3
  •  5
  •   Toby    11 年前

    void Main()
    {
        ConvertSql(System.Windows.Forms.Clipboard.GetText()).Dump();
    }
    
    private static string ConvertSql(string origSql)
    {
      string tmp = origSql.Replace("''", "~~");       
      string baseSql;
      string paramTypes;
      string paramData = "";
      int i0 = tmp.IndexOf("'") + 1;
      int i1 = tmp.IndexOf("'", i0);
      if (i1 > 0)
      {
          baseSql = tmp.Substring(i0, i1 - i0); 
          i0 = tmp.IndexOf("'", i1 + 1);
          i1 = tmp.IndexOf("'", i0 + 1);
          if (i0 > 0 && i1 > 0)
          {
              paramTypes = tmp.Substring(i0 + 1, i1 - i0 - 1);
              paramData = tmp.Substring(i1 + 1);
          }
      }
      else
      {
          throw new Exception("Cannot identify SQL statement in first parameter");
      }
    
      baseSql = baseSql.Replace("~~", "'");  
      if (!String.IsNullOrEmpty(paramData))  
      {
          string[] paramList = paramData.Split(",".ToCharArray());
          foreach (string paramValue in paramList)
          {
              int iEq = paramValue.IndexOf("=");
              if (iEq < 0)
                  continue;
              string pName = paramValue.Substring(0, iEq).Trim();
              string pVal = paramValue.Substring(iEq + 1).Trim();
              baseSql = baseSql.ReplaceWholeWord(pName, pVal);
          }
      }
    
      return baseSql;
    }
    
    public static class StringExtensionsMethods
    {
       /// <summary>
       /// Replaces the whole word.
       /// </summary>
       /// <param name="s">The s.</param>
       /// <param name="word">The word.</param>
       /// <param name="replacement">The replacement.</param>
       /// <returns>String.</returns>
       public static String ReplaceWholeWord(this String s, String word, String replacement)
       {
           var firstLetter = word[0];
           var sb = new StringBuilder();
           var previousWasLetterOrDigit = false;
           var i = 0;
           while (i < s.Length - word.Length + 1)
           {
               var wordFound = false;
               var c = s[i];
               if (c == firstLetter)
                   if (!previousWasLetterOrDigit)
                       if (s.Substring(i, word.Length).Equals(word))
                       {
                           wordFound = true;
                           var wholeWordFound = true;
                           if (s.Length > i + word.Length)
                           {
                               if (Char.IsLetterOrDigit(s[i + word.Length]))
                                   wholeWordFound = false;
                           }
    
                           sb.Append(wholeWordFound ? replacement : word);
    
                           i += word.Length;
                       }
    
               if (wordFound) continue;
    
               previousWasLetterOrDigit = Char.IsLetterOrDigit(c);
               sb.Append(c);
               i++;
           }
    
           if (s.Length - i > 0)
               sb.Append(s.Substring(i));
    
           return sb.ToString();
       }
    }
    
        4
  •  4
  •   Will L Alex Vazhev    7 年前

    https://code.msdn.microsoft.com/windowsdesktop/spExecuteSql-parser-1a9cd7bc

    exec sp_executesql N'UPDATE Task SET Status = @p0, Updated = @p1 WHERE Id = @p2 AND Status = @p3 AND Updated = @p4',N'@p0 int,@p1 datetime,@p2 int,@p3 int,@p4 datetime',@p0=1,@p1='2015-02-07 21:36:30.313',@p2=173990,@p3=2,@p4='2015-02-07 21:35:32.830'
    

    UPDATE Task SET Status = 1, Updated = '2015-02-07 21:36:30.313' WHERE Id = 173990 AND Status = 2 AND Updated = '2015-02-07 21:35:32.830'
    

    这使得它更容易理解。

    sp_executesql

    为了提高可读性,还可以在该解决方案中添加SQL格式化程序:

    http://www.nuget.org/packages/PoorMansTSQLFormatter/

    newSql = ConvertSql(Clipboard.GetText());
    var formattedSql = SqlFormattingManager.DefaultFormat(newSql);
    Clipboard.SetText(formattedSql);
    
        6
  •  1
  •   buckley    9 年前

        7
  •  0
  •   Alex141    9 年前

    一些正则表达式和一些字符串连接,然后将其出售给Vinko和其他寻求此功能的人。

    http://sqlblogcasts.com/blogs/jonsayce/archive/2008/01/15/building-a-sql-server-management-studio-addin.aspx

        8
  •  0
  •   marc_s MisterSmith    9 年前

    ClipboardSqlFormatter 这是一个托盘应用程序,它监听剪贴板输入事件,并尝试检测动态sql并将其转换为静态sql。

    您需要做的就是复制动态sql(例如从sql分析器)并粘贴到文本编辑器中——粘贴的sql将是静态sql:)

    例如,如果复制的sql是:

    exec sp_executesql N' SELECT "obj"."CreateDateTime", "obj"."LastEditDateTime" FROM LDERC "doc" INNER JOIN LDObject "obj" ON ("doc"."ID" = "obj"."ID") LEFT OUTER JOIN LDJournal "ContainerID.jrn" ON ("doc"."JournalID" = "ContainerID.jrn"."ID") WHERE ( "doc"."ID" = @V0 AND ( "doc"."StateID" <> 5 AND "ContainerID.jrn"."Name" <> ''Hidden journal'' ) ) ',N'@V0 bigint',@V0=6815463'

    SELECT "obj"."CreateDateTime" ,"obj"."LastEditDateTime" FROM LDERC "doc" INNER JOIN LDObject "obj" ON ("doc"."ID" = "obj"."ID") LEFT OUTER JOIN LDJournal "ContainerID.jrn" ON ("doc"."JournalID" = "ContainerID.jrn"."ID") WHERE ( "doc"."ID" = 6815463 AND ( "doc"."StateID" <> 5 AND "ContainerID.jrn"."Name" <> 'Hidden journal' ) )

        9
  •  0
  •   Pejman Nikram    7 年前

    结论:我注意到这仍然受到了一些关注,所以我将在这里添加详细信息,说明我最终的解决方案是什么。

    class Program
    {
        const string query = "query";
        const string decls = "decls";
        const string sets = "sets";
        static void Main(string[] args)
        {
            try
            {
                var text = File.ReadAllText(args[0]);
                if(string.IsNullOrEmpty(text))
                {
                    Console.WriteLine("File is empty.  Try saving it before using the hillbilly sproc decoder");
                }
                var regex = new Regex(@"exec sp_executesql N'(?<" + query + ">.*)',N'(?<" + decls + ">[^']*)',(?<" + sets + ">.*)", RegexOptions.Singleline);
                var match = regex.Match(text);
    
                if(!match.Success || match.Groups.Count != 4)
                {
                    Console.WriteLine("Didn't capture that one.  Shit.");
                    Console.Read();
                    return;
                }
    
                var sb = new StringBuilder();
                sb.Append("DECLARE ").AppendLine(match.Groups[decls].Value);
                foreach(var set in match.Groups[sets].Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                    sb.Append("SET ").AppendLine(set);
                sb.AppendLine(match.Groups[query].Value.Replace("''", "'"));
                File.WriteAllText(args[0], sb.ToString());
            }
            catch(Exception ex)
            {
                Console.WriteLine("S*t blew up, yo");
                Console.WriteLine(ex.ToString());
                Console.WriteLine("Press a key to exit");
                Console.Read();
            }
        }
    }