Pergunta

Ao lidar com consultas depuração usando Profiler e SSMS, o seu muito comum para mim para copiar uma consulta a partir Profiler e testá-los em SSMS. Porque eu uso SQL parametrizado, minhas consultas são todos enviados como consultas exec sp_executesql.

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

Vou levar este e convertê-lo em uma consulta normal para facilitar a edição (intellisense, verificação de erros, números de linha, etc):

DECLARE @someParameter tinyint
SET @someParameter = 2

/*some query here*/

É claro, a maior e mais complexa a consulta, o mais difícil de fazer isso. E quando você está indo e voltando várias vezes, ele pode ser um pé no saco e absorver lotes de tempo.

Existe uma (por exemplo, comando de macro) maneira fácil para converter ExecuteSQL muh em algo mais conveniente?

Foi útil?

Solução

Não tenho conhecimento de um suplemento existente que pode fazer isso. Mas você poderia criar um:)

Algumas expressões regulares e alguns concatenação e depois que vendê-lo para Vinko e outras almas olhando para essa funcionalidade.

Se você está se sentindo como mergulhar isso, aqui estão algumas informações sobre a criação de um SSMS Addin: http: //sqlblogcasts.com/blogs/jonsayce/archive/2008/01/15/building-a-sql-server-management-studio-addin.aspx

Outras dicas

Eu passei um pouco de tempo fazendo um script simples que fez isso por mim. É um WIP, mas eu furei uma página web (muito feio) na frente dele e ele está agora hospedado aqui se você quiser experimentá-lo:

http://execsqlformat.herokuapp.com/

de entrada da amostra:

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

E a saída:

BEGIN
DECLARE @level tinyint;

SET @level = 109;

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

A formatação da instrução SQL real uma vez que eu arrancou a partir da entrada é feito usando a API em http: // sqlformat.appspot.com

Eu estava procurando por algo semelhante, então eu usar isso em LinqPad, basta copiar declaração sp_executesql para a área de transferência e execute o código na LinqPad. Ele produz a instrução 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();
   }
}

Eu passei um pouco de tempo e criou uma pequena modificação de soluções de Matt Roberts / Wangzq sem seção declara, você pode experimentá-lo em .NET Fiddle ou de download LINQPad 5 arquivo .

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

Código:

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

Outra solução que substitui os valores dos parâmetros diretamente na consulta (Não exatamente o que você pediu, mas pode ser útil para os outros):

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

I vai de:

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'

para:

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'

que torna mais fácil de entender.

O aplicativo de console nessa página pode ser usado passando um parâmetro arquivo ou copiar o sp_executesql na área de transferência, a execução do aplicativo e, em seguida, colar o SQL resultante da área de transferência.

Update:

formatador Um SQL também pode ser adicionada a essa solução para facilitar a leitura mais fácil:

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

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

Sql Got Prompt esse recurso recentemente (2017/02/06). Selecione o texto e olhar para "inline EXEC" no menu de contexto. Conseguiu amar Prompt:)

I confrontados com este problema e também escreveu aplicação simples para resolvê-lo - ClipboardSqlFormatter . Esta é uma aplicação da bandeja que eventos de entrada escutas área de transferência e tenta detectar e convertido dinâmica sql para estático sql.

Qualquer coisa que você precisa é copiar sql dinâmico (a partir profiler sql por exemplo) e colar para texto editor - colado sql será um sql estática:)

Por exemplo, se o SQL copiado é:

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, em seguida, colado será:

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

Você pode usar essa extensão estúdio de dados Azur. -lo com base na @ Matt Roberts repo. https://github.com/PejmanNik/sqlops- spexecutesql-to-sql / releases / tag / 0.0.1

enter descrição da imagem aqui

Conclusão:. I, note que este ainda fica um pouco de atenção, então eu vou adicionar detalhes aqui para que o meu eventual solução era

Acontece que bate nada fazendo isso para si mesmo. Eu criei um aplicativo de console simples que analisado o meu procedimento armazenado e cuspir para fora o que eu queria. Adicionando-o à lista de ferramentas externas, e passando o nome do arquivo atual como um argumento, eu poderia usar o seguinte para retirar e reorganizar o que eu precisava.

Em uso, eu adicionar um novo arquivo sql, colar no sql, salvá-lo, em seguida, executar a ferramenta externa. Depois que ele for concluído, o IDE me pede para recarregar o arquivo. Poof, o procedimento não mais armazenados.

Eu faço nota que este pode não funcionar com todas declaração ExecuteSQL, então você vai ter que modificar se ele não atender às suas necessidades.

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();
        }
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top