31

プロファイラーとSSMSを使用してクエリのデバッグを処理する場合、プロファイラーからクエリをコピーしてSSMSでテストすることは非常に一般的です。パラメータ化されたSQLを使用しているため、クエリはすべてexecsp_executesqlクエリとして送信されます。

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

これを取得して、編集を容易にするために通常のクエリに変換します(インテリセンス、エラーチェック、行番号など)。

DECLARE @someParameter tinyint
SET @someParameter = 2

/*some query here*/

もちろん、クエリが大きく複雑になるほど、これを行うのは難しくなります。そして、あなたが何度も行ったり来たりしているとき、それはお尻の痛みであり、多くの時間を吸収する可能性があります。

muh executesqlをより便利なものに変換する簡単な(たとえば、マクロコマンド)方法はありますか?

4

10 に答える 10

44

私はこれを行う簡単なスクリプトを作成するのに少し時間を費やしました。これはWIPですが、その前に(非常に醜い)Webページを貼り付けました。試してみたい場合は、ここでホストされています。

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ステートメントのフォーマットは、http://sqlformat.appspot.comのAPIを使用して行われます。

于 2011-12-20T20:42:01.567 に答える
6

私は少し時間を費やして、DECLAREsセクションのないMatt Roberts / Wangzqソリューションの小さな変更を作成しました。.NETFiddleで試すか、LINQPad5ファイルダウンロードできます

入力:

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.";
    }
}
于 2016-11-03T13:54:04.563 に答える
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();
   }
}
于 2015-05-19T11:23:01.493 に答える
4

クエリ内のパラメータ値を直接置き換える別のソリューション(正確には要求したものではありませんが、他の人にとっては役立つ場合があります):

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をクリップボードから貼り付けることで使用できます。

アップデート:

読みやすくするために、SQLフォーマッターをそのソリューションに追加することもできます。

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

newSql = ConvertSql(Clipboard.GetText());
var formattedSql = SqlFormattingManager.DefaultFormat(newSql);
Clipboard.SetText(formattedSql);
于 2015-02-08T05:59:00.157 に答える
3

このAzurデータスタジオ拡張機能を使用できます。@MattRobertsリポジトリに基づいています。 https://github.com/PejmanNik/sqlops-spexecutesql-to-sql/releases/tag/0.0.1

ここに画像の説明を入力してください

于 2018-11-30T13:47:59.270 に答える
2

SQLプロンプトは最近この機能を取得しました(2017-02-06)。テキストを選択し、コンテキストメニューで「インラインEXEC」を探します。プロンプトが大好きです:)

于 2017-02-06T08:48:28.807 に答える
1

これを実行できる既存のアドインを認識していません。しかし、あなたはそれを作成することができます:)

いくつかの正規表現といくつかの文字列の連結、そしてその後、この機能を探しているVinkoや他の魂にそれを売ります。

これに飛び込みたい場合は、SSMSアドインの作成に関する情報を以下に示します。http: //sqlblogcasts.com/blogs/jonsayce/archive/2008/01/15/building-a-sql-server-management- studio-addin.aspx

于 2009-07-18T18:56:30.183 に答える
1

結論:これはまだ少し注目されているので、最終的な解決策についてここに詳細を追加します。

自分でやるのに勝るものはありません。ストアドプロシージャを解析し、必要なものを吐き出すシンプルなコンソールアプリを作成しました。これを外部ツールのリストに追加し、現在のファイル名を引数として渡すことで、次のコマンドを使用して、必要なものを取り除き、再配置することができます。

使用中は、新しいSQLファイルを追加し、SQLを貼り付けて保存してから、外部ツールを実行します。完了すると、IDEはファイルをリロードするように要求します。Poof、これ以上のストアドプロシージャはありません。

これはすべてのexecutesqlステートメントで機能するとは限らないため、ニーズに合わない場合は変更する必要があることに注意してください。

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();
        }
    }
}
于 2016-11-03T14:43:40.087 に答える
1

私もこの問題に直面し、それを解決するための簡単なアプリケーションを作成しました-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'

次に、貼り付けられた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' ) )

于 2017-02-12T23:03:02.180 に答える
1

これは、NHibernateクエリを検査するために使用する単純なUIです。sqlを美化するためのいくつかの正規表現、構文解析、および sqlformat.orgAPIが使用されます。

<html>
<head>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script type="text/javascript">
        $(function(){
            $("#btn-format").on("click", () =>{
                var insql = $("#textarea-in").val();        

                var regex = new RegExp("exec sp_executesql N'(?<command>.+?(?='(,N'$)?))'(,\s*N'(?<types>.+?(?=',))',\s*(?<vals>.+))?");
                var groups = insql.replace(/\n|\r/g, "").match(regex).groups;

                var outsql = "";
                if (groups.types)
                {
                    var types = groups.types.match(/@[^\s]+ \w+(\([\w\d,]+\))?/g);
                    for (const typeDeclaration of types) {
                        outsql = outsql + 'declare ' +  typeDeclaration + '\n';
                    }
                    outsql = outsql + '\n';
                    for (const setVal of groups.vals.split(',')) {
                        outsql = outsql + 'set ' +  setVal + '\n';
                    }
                    outsql = outsql + '\n';
                }
                $.ajax({
                    url: 'https://sqlformat.org/api/v1/format',
                    type: 'POST',
                    dataType: 'json',
                    crossDomain: true,
                    data: {
                        sql: groups.command, reindent: 1
                    },
                    success: (data) => {
                        outsql = outsql + data.result;
                        $("#textarea-out").val(outsql);
                    },
                    error: () =>{
                        outsql = outsql + '-- No format happened. See browser console for details \n';
                        outsql = outsql + groups.command;
                        $("#textarea-out").val(outsql);
                    }
                });        
            })    
        });
    </script>        
</head>
<body>
    <textarea id="textarea-in" style="width: 100%; height: 48%;" class="form-control" placeholder="type 'exec sp_executesql...' here"></textarea>
    <br/>
    <button id="btn-format">Format</button>
    <br/>
    <textarea id="textarea-out" style="width: 100%; height: 48%;" class="form-control"></textarea>
</body>

フィドルでテスト

注:クエリに一重引用符がある場合は機能しません

于 2020-03-16T12:00:46.707 に答える