1

実行時まで認識されないSQLSELECTステートメントがあります。これには、JOINと内部選択が含まれている可能性があります。C#内から、ステートメントの返された結果の各列の名前とデータ型を判別する必要があります。私は次のようなことをする傾向があります:

string orginalSelectStatement = "SELECT * FROM MyTable";

string selectStatement = string.Format("SELECT TOP 0 * FROM ({0}) s", orginalSelectStatement);
SqlConnection connection = new SqlConnection(@"MyConnectionString");
SqlDataAdapter adapter = new SqlDataAdapter(selectStatement, connection);

DataTable table = new DataTable();
adapter.Fill(table);

foreach (DataColumn column in table.Columns)
{
    Console.WriteLine("Name: {0}; Type: {1}", column.ColumnName, column.DataType);
}

私がやろうとしていることをするためのより良い方法はありますか?「より良い」とは、同じタスクを実行するためのリソースをあまり消費しない方法、または同じタスクを実行するためのより確実な方法のいずれかを意味します(つまり、私が今与えたコードスニペットが状況によっては失敗することを私は知っています)。

解決策:まず第一に、私のTOP 0ハックは悪いです、つまりこのようなもののために:

SELECT TOP 0 * FROM (SELECT 0 AS A, 1 AS A) S

つまり、副選択で2つのものが同じ名前にエイリアスされている場合、エラーがスローされます。だから、それは絵の外です。SET FMTONLY ONただし、完全を期すために、提案された2つのソリューション(および)とともに、先に進んでテストしました GetSchemaTable

結果は次のとおりです(それぞれ1,000クエリのミリ秒単位)。

スキーマ時間:3130

TOP 0時間:2808

FMTONLY ON Time:2937

GetSchemaTable有効なSQLを削除することで将来にわたって利用できる可能性が高くなり、SET FMTONLY ON少し遅くなりますが、エイリアシングの問題が解決 されるため、私の推奨事項です。ただし、重複する列名が問題になることは決してないことを「知っている」場合TOP 0は、よりも高速でGetSchemaTableあり、より将来にわたって利用できSET FMTONLY ONます。

これが私の実験コードです:

int schemaTime = 0;
int topTime = 0;
int fmtOnTime = 0;

SqlConnection connection = new SqlConnection(@"MyConnectionString");
connection.Open();

SqlCommand schemaCommand = new SqlCommand("SELECT * FROM MyTable", connection);
SqlCommand topCommand = new SqlCommand("SELECT TOP 0 * FROM (SELECT * FROM MyTable) S", connection);
SqlCommand fmtOnCommand = new SqlCommand("SET FMTONLY ON; SELECT * FROM MyTable", connection);

for (int i = 0; i < 1000; i++)
{
    {
        DateTime start = DateTime.Now;
        using (SqlDataReader reader = schemaCommand.ExecuteReader(CommandBehavior.SchemaOnly))
        {
            DataTable table = reader.GetSchemaTable();
        }
        DateTime stop = DateTime.Now;
        TimeSpan span = stop - start;
        schemaTime += span.Milliseconds;
    }

    {
        DateTime start = DateTime.Now;

        DataTable table = new DataTable();
        SqlDataAdapter adapter = new SqlDataAdapter(topCommand);
        adapter.Fill(table);

        DateTime stop = DateTime.Now;
        TimeSpan span = stop - start;
        topTime += span.Milliseconds;
    }

    {
        DateTime start = DateTime.Now;

        DataTable table = new DataTable();
        SqlDataAdapter adapter = new SqlDataAdapter(fmtOnCommand);
        adapter.Fill(table);

        DateTime stop = DateTime.Now;
        TimeSpan span = stop - start;
        fmtOnTime += span.Milliseconds;
    }
}

Console.WriteLine("Schema Time: " + schemaTime);
Console.WriteLine("TOP 0 Time: " + topTime);
Console.WriteLine("FMTONLY ON Time: " + fmtOnTime);

connection.Close();
4

3 に答える 3

5

GetSchemaTableを使用して、必要なことを実行できます。

ここにそれを使用する方法の例があります。

于 2012-04-18T19:38:29.093 に答える
2

SQL Serverを使用している場合は、SETFMTONLYONを使用してみます

メタデータのみをクライアントに返します。実際にクエリを実行せずに、応答の形式をテストするために使用できます。

どうやらSQLServer2012には、もっと良い方法があります。すべては、リンクされたMSDNの記事で指定されています。

ところで、この手法は、LINQToSQLがストアドプロシージャなどによって返される結果セットを決定するために内部的に使用するものです。

于 2012-04-18T19:41:07.727 に答える
0

動的SQLは常にちょっとした地雷原ですが、クエリでSET FMTONLY ONを使用できます。これは、結果が返されない場合と同じように、クエリがメタデータのみを返すことを意味します。それで:

string selectStatement = string.Format("SET FMTONLY ON; {0}", orginalSelectStatement);

あるいは、ADOに縛られていない場合は、LinqからSQLへのルートをたどって、すべてのデータベーススキーマをコードとそれに関連するタイプにマップするデータコンテキストを生成できませんか?また、Dapper.NetなどのMicroORMのいくつかを見ることができます。

他にもたくさんのORMがあります。

于 2012-04-18T19:53:32.463 に答える