2009-07-16 6 views
22

При работе с отладочными запросами с использованием Profiler и SSMS довольно часто для меня копировать запрос из Profiler и тестировать их в SSMS. Поскольку я использую параметризованный sql, мои запросы отправляются как exec sp_executesql.Простой способ преобразования exec sp_executesql в обычный запрос?

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

Я возьму это и преобразовать его в обычный запрос для удобства редактирования (IntelliSense, проверка на наличие ошибок, номера строк и т.д.):

DECLARE @someParameter tinyint 
SET @someParameter = 2 

/*some query here*/ 

Конечно, все больше и более сложной запрос, тем сложнее сделать это. И когда вы идете туда и обратно несколько раз, это может быть боль в заднице и впитывать много времени.

Есть ли простой способ (например, макрокоманда) для преобразования muh executesql во что-то более удобное?

+0

+1 Я хотел бы, что хорошо –

+0

+1 Seconded on lovin 'this –

+0

Вы должны рассмотреть возможность размещения своего окончательного решения в качестве * ответа * ... – Shog9

ответ

1

Мне не известно о существующей надстройке, которая может это сделать. Но вы можете создать один :)

Несколько регулярных выражений и некоторая строка конкатенации и после этого продают его Vinko и другим душам, ищущим эту функциональность.

Если вы чувствуете, как нырнуть в это, вот некоторая информация о создании надстройки SSMS: http://sqlblogcasts.com/blogs/jonsayce/archive/2008/01/15/building-a-sql-server-management-studio-addin.aspx

27

Я провел немного времени, сделав простой сценарий, который сделал это для меня. Это WIP, но я застрял (очень некрасиво) веб-страницы перед ним, и он теперь размещается здесь, если вы хотите попробовать:

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 

форматирование фактического заявления SQL, как только я вынул ее из ввода делается с помощью API на http://sqlformat.appspot.com

+0

Привет, Мэтт, меня очень интересует, как вы использовали api для преобразования sp_executesql, можете ли вы поделиться своим кодом? Благодаря! – wangzq

+2

Вложил в git репо, чтобы вы могли;) https://github.com/mattwoberts/execsqlformat –

+0

Спасибо! Хорошо знать, что вы используете регулярное выражение для синтаксического анализа ввода. – wangzq

3

Еще одно решение, которое заменяет значения параметров непосредственно в запросе (не совсем то, что вы просили, но это может оказаться полезным для других):

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' 

, который ма kes легче понять.

Консольное приложение на этой странице можно использовать, передав параметр файла или скопировав sp_executesql в буфер обмена, запустив приложение, а затем вставив полученный SQL из буфера обмена.

Update:

SQL-форматировщик также могут быть добавлены к этому раствору для облегчения читаемости:

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

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

Я искал что-то подобное, поэтому я использую это в LINQPad , просто скопируйте оператор sp_executesql в буфер обмена и запустите код в LinqPad. Он выводит инструкцию 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

Я потратил немного времени и создал небольшую модификацию решений Matt Roberts/Wangzq без раздела Объявляет, вы можете попробовать его на .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."; 
    } 
0

Заключение: Я отмечаю это все еще получает мало внимания, поэтому я буду добавлять детали здесь для чего мое возможное решение было.

Получается, что ничего не бьет, делая это для себя. Я создал простое консольное приложение, которое проанализировало мою хранимую процедуру и выплевывало то, что я хотел. Добавив его в список внешних инструментов и передав текущее имя файла в качестве аргумента, я мог бы использовать следующее, чтобы разграничить и изменить то, что мне нужно.

В использовании я бы добавил новый sql-файл, вставив его в sql, сохранил его и запустил внешний инструмент. После его завершения IDE просит меня перезагрузить файл. Пуф, больше не хранится процедура.

Обработка исключений и другие материалы удалены, и я замечаю, что это может не работать с каждые executesql, поэтому вам придется изменить, если это не соответствует вашим потребностям.

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, вы так сильно ненавидите sprocs? – Will

+0

Да, Воля, я знаю. –

0

Sql Prompt получил эту функцию недавно (2017-02-06). Выберите текст и найдите «Inline EXEC» в контекстном меню. Gotta love Prompt :)

0

Я столкнулся с этой проблемой и написал простое приложение для ее решения - ClipboardSqlFormatter. Это приложение лотка, которое прослушивает события ввода буфера обмена и пытается обнаружить и преобразовать динамический sql в статический sql.

Все, что вам нужно, чтобы скопировать динамический SQL (из SQL Profiler, например) и вставить в текстовый редактор - вставили 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'

затем вставили SQL будет:

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

 Смежные вопросы

  • Нет связанных вопросов^_^