2009-07-16 43 views
22

Khi xử lý các truy vấn gỡ rối bằng Profiler và SSMS, nó khá phổ biến đối với tôi để sao chép truy vấn từ Profiler và kiểm tra chúng trong SSMS. Bởi vì tôi sử dụng tham số sql, truy vấn của tôi là tất cả được gửi như exec sp_executesql truy vấn.Cách dễ dàng để chuyển đổi exec sp_executesql thành một truy vấn bình thường?

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

tôi sẽ thực hiện việc này và chuyển đổi nó thành một truy vấn bình thường để dễ chỉnh sửa (IntelliSense, kiểm tra lỗi, số dòng, vv):

DECLARE @someParameter tinyint 
SET @someParameter = 2 

/*some query here*/ 

Tất nhiên, khu phức hợp lớn hơn và nhiều hơn nữa truy vấn, khó thực hiện việc này hơn. Và khi bạn đang đi lại nhiều lần, nó có thể là một nỗi đau trong ass và hấp thụ rất nhiều thời gian.

Có cách nào dễ dàng (ví dụ: lệnh macro) để chuyển đổi muh executesql thành một thứ tiện lợi hơn không?

+0

+1 tôi muốn yêu mà cũng –

+0

+1 Được yêu thích là –

+0

Bạn nên cân nhắc việc đăng giải pháp cuối cùng của mình dưới dạng câu trả lời * ... – Shog9

Trả lời

1

Tôi không biết về Trình bổ sung hiện tại có thể thực hiện việc này. Nhưng bạn có thể tạo một cái :)

Một vài biểu thức chính quy và một số chuỗi nối và sau đó bán nó cho Vinko và các linh hồn khác tìm kiếm chức năng này.

Nếu bạn đang cảm thấy như lặn vào trong này, đây là một số thông tin về việc tạo ra một addin SSMS: http://sqlblogcasts.com/blogs/jonsayce/archive/2008/01/15/building-a-sql-server-management-studio-addin.aspx

27

tôi đã dành một ít thời gian thực hiện một kịch bản đơn giản mà đã làm điều này cho tôi. Đó là một WIP, nhưng tôi bị mắc kẹt một (rất xấu xí) trang web trước đó và nó hiện nay tổ chức ở đây nếu bạn muốn thử nó:

http://execsqlformat.herokuapp.com/

mẫu đầu vào:

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

Và đầu ra:

BEGIN 
DECLARE @level tinyint; 

SET @level = 109; 

SELECT * FROM AdventureWorks.HumanResources.Employee 
      WHERE ManagerID = @level 
END 

các định dạng của các câu lệnh SQL thực tế sau khi đã hái nó từ đầu vào được thực hiện bằng cách sử dụng API tại http://sqlformat.appspot.com

+0

Xin chào Matt, tôi rất quan tâm đến cách bạn sử dụng api để chuyển đổi sp_executesql, bạn có thể chia sẻ mã của mình không? Cảm ơn! – wangzq

+2

Bung nó vào một repo git cho bạn thưởng thức;) https://github.com/mattwoberts/execsqlformat –

+0

Cảm ơn! Nó là tốt để biết bạn đang sử dụng regex để phân tích đầu vào đầu tiên. – wangzq

3

Một giải pháp thay thế các giá trị tham số trực tiếp trong truy vấn (không chính xác những gì bạn yêu cầu nhưng nó có thể hữu ích cho người khác):

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

Tôi đi từ:

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' 

tới:

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' 

mà ma kes nó dễ hiểu hơn. Bạn có thể sử dụng ứng dụng bảng điều khiển trên trang đó bằng cách chuyển thông số tệp hoặc sao chép sp_executesql trong khay nhớ tạm, chạy ứng dụng và sau đó dán SQL kết quả từ khay nhớ tạm thời.

Cập nhật:

Một định dạng SQL cũng có thể được thêm vào rằng giải pháp để có thể đọc dễ dàng hơn:

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

newSql = ConvertSql(Clipboard.GetText()); 
var formattedSql = SqlFormattingManager.DefaultFormat(newSql); 
Clipboard.SetText(formattedSql); 
5

tôi đang tìm kiếm một cái gì đó tương tự vì vậy tôi sử dụng này trong LinqPad , chỉ cần sao chép sp_executesql tuyên bố vào clipboard và chạy mã trong LinqPad. Nó đưa ra câu lệnh SQL.

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(); 
    } 
} 
3

tôi đã dành một ít thời gian và tạo ra một thay đổi nhỏ của giải pháp Matt Roberts/Wangzq mà không tuyên bố phần, bạn có thể thử nó trên .NET Fiddle hoặc download LINQPad 5 file.

Input:

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

Output:

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

Code:

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."; 
    } 
0

Kết luận: Tôi lưu ý này vẫn nhận được một sự chú ý rất ít vì vậy tôi sẽ thêm chi tiết tại đây cho những gì giải pháp cuối cùng của tôi là.

Nó chỉ ra rằng không có gì nhịp đập làm điều đó cho chính mình. Tôi đã tạo một ứng dụng giao diện điều khiển đơn giản phân tích thủ tục được lưu trữ của tôi và nhổ ra những gì tôi muốn. Bằng cách thêm nó vào danh sách các công cụ bên ngoài và chuyển tên tệp hiện tại làm đối số, tôi có thể sử dụng các phần sau để loại bỏ và sắp xếp lại những gì tôi cần.

Khi sử dụng, tôi sẽ thêm một tệp sql mới, dán vào sql, lưu nó, sau đó chạy công cụ bên ngoài. Sau khi nó hoàn thành, IDE yêu cầu tôi tải lại tệp. Poof, không có thủ tục lưu trữ nhiều hơn nữa.

Xử lý ngoại lệ và các nội dung khác bị loại bỏ và tôi lưu ý rằng điều này có thể không hoạt động với mỗi câu lệnh executesql, vì vậy bạn sẽ phải sửa đổi nếu nó không đáp ứng nhu cầu của bạn.

var text = File.ReadAllText(args[0]); 
if(string.IsNullOrEmpty(text)) 
{ 
    Console.WriteLine(
     "File is empty; try saving it before using the hillbilly stored procedure 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."); 
    Console.Read(); 
    return; 
} 

var sb = new StringBuilder(); 
// declares go on top 
sb.Append("DECLARE ").AppendLine(match.Groups["decls"].Value); 
// split out our sets, add them one line at a time 
foreach(var set in match.Groups["sets"] 
        .Value.Split(new char[] { ',' }, 
        StringSplitOptions.RemoveEmptyEntries)) 
    sb.Append("SET ").AppendLine(set); 
// Add our query, removing double quotes 
sb.AppendLine(match.Groups["query"].Value.Replace("''", "'")); 
File.WriteAllText(args[0], sb.ToString()); 
+0

Jeez, @marc, bạn có ghét sprocs nhiều không? – Will

+0

Có, tôi sẽ làm. –

0

Sql Đã có tính năng này gần đây (2017-02-06). Chọn văn bản và tìm "Inline EXEC" trong menu ngữ cảnh. Gotta love Prompt :)

0

Tôi cũng phải đối mặt với vấn đề này và viết đơn giản để giải quyết nó - ClipboardSqlFormatter. Đây là một ứng dụng khay lắng nghe các sự kiện đầu vào clipboard và cố gắng phát hiện và chuyển đổi sql động sang sql tĩnh.

Bất cứ điều gì bạn cần là để sao chép sql động (từ profiler sql chẳng hạn) và dán để soạn thảo văn bản - sql dán sẽ là một sql tĩnh :)

Ví dụ, nếu sql sao chép là:

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'

sau đó sql dán sẽ là:

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' ) )

Các vấn đề liên quan