2012-01-30 16 views
2

私の問題は本質的に単純です - データベースを照会し、一連のファイル(〜1000)に出力を書き込みます。C#と長いSQL Serverクエリ、これを行う正しい方法は何ですか?

SQL ServerでC#から実行する必要があるSQLクエリがあります。クエリは、IN節の値の1つを除いて、かなり簡単です。

例として、クエリは次のようになります。値のリストが6つの文字それぞれ約300の文字列である

SELECT 
    ID, Name 
FROM 
    MyTable 
WHERE 
    SomeValue IN (/* list of values */) 

。値は最終的には( "A00001"、 "A00002"など)のようになり、アプリケーションのユーザーによって入力として指定されます。

私の最初の考えは、それぞれの値をまとめた長い文字列としてクエリを構築することでした。しかし、これは適切なアプローチのようには見えず、エラーが起こりやすいようです。私の次の考えはストアドプロシージャを使用することでしたが、データをどのようにそれに渡すべきかはわかりません。データが確実に渡される効率的な方法で、このクエリをどのように構築する必要がありますか?

私の他の選択肢は、SQL Serverからすべてのデータを読み込み、C#で結果をフィルタリングすることです。しかし、私がこれを行うと、約9百万のレコードが得られ、データセットとしてメモリに読み込むには多すぎるようです。 〜5000のレコードを解析した後にファイルを作成しているため、受信しているデータを噛み砕いている間に、データ・リーダーをデータベースに接続したままにしたくありません。

最良のアプローチは何ですか?あなたがそれを行うことができない場合

SELECT ProductID from Product where ManufacturerID in 
    (SELECT ManufacturerID from Manufacturer where HomeOfficeLocation = 'France') 

:限り、ユーザーはあなたが提供してきましたリスト、簡単な連結されたリストから選んでいるよう

+0

あなたのデータがユーザの入力から来ている場合は、SQLインジェクション攻撃を避けるためにあなたの入力を注意深く浄化したいと思うでしょう。両方とも典型的なSQLインジェクションに対する効果的な手段であるため、バインド変数または一時テーブルを使用する方がよいかもしれません。 – LBushkin

+0

データベースの操作にはどのようなものがありますか?両方 - "私は文字列としてクエリをまとめる"と "私は何をすべきか分かっているのでLINQを使う"ということは、入力の型の配列を与えて効率的に行うことができるということです。このフォームに申請書を入力することは、初年度IT学生のための文字列操作の宿題です。だから、問題はどうですか? – TomTom

+0

@TomTom問題は私が財務報告を生成しており、入力がSSRSが処理するのが難しいことに終わります。その上に、出力は一連のExcelファイルです。入力パラメータは、ユーザが報告することを望むバーコードのリストとして考えることができる。実際のクエリとサンプル入力を提供することは、あまりにも多くの不要な複雑さを問題に追加します。私はすでにクエリを書いて実行する方法を知っています。私が知りたいのは、〜10000文字列をクエリとして効率的に処理する方法、または6000文字列をストアドプロシージャに渡す方法です。 –

答えて

1

は、XMLを使用してそれを行うための一つの方法です:

C#:

StringBuilder sb = new StringBuilder(); 
sb.AppendLine("<SelectedValues>"); 

foreach (string s in userSelectedValues) 
    sb.AppendFormat("<row val=\"{0}\" />{1}", s, Environment.NewLine); 
sb.AppendLine("</SelectedValues>"); 

峠このsb.ToString()ストアドプロシージャ

SQL TO XML AS:

CREATE PROCEDURE dbo.MyStoredProcedure 
(
    @UserSelectedValuesXml XML 
)  

SELECT * 
FROM dbo.MyTable 
WHERE Id IN (SELECT ref.value('@val', 'varchar') 
       FROM @UserSelectedValuesXml.nodes('/SelectedValues/row') AS T(ref)) 
+0

これはテーブル値のパラメータよりも速いでしょうか? –

+0

@Joeは、XMLまたは大きなVARCHARとして送信する必要があるストアドプロシージャにリストを送信するには、xmlを取得してテーブル値パラメータにダンプすることができますが、このステップにはこの要素が必要です。 –

+0

エンジニアと彼はテーブル値のパラメータを超えてXMLメソッドを提案しました。ありがとう! –

2

通常の方法は、IN句にサブクエリを作ることです特にエラーを起こしやすいというわけではありません。

間違いなくを入力しないでください小さなデータセットを探して大きなデータセットをループしたいと考えています。私は頻繁に行うことは、フロントエンド(旧"234, 345, 456")で、カンマ区切りのリストを作成し、文字列としてストアドプロシージャにそれを渡している。もう少し完全なものにするに

を追加する

編集;そのprocの内部では、hereのようなユーザー定義関数を使用します。

私は一時テーブルに対して何も持っていませんが、通常はリスト上で複数の操作を行う場合にのみ使用します。

「ユーザーがリストから選択している限り」という理由は、ユーザーの入力を検証(および消毒)する必要がないためです。

+0

これは、値がアプリケーションから渡されるので、このためのテーブルを作成する必要があります – JNK

+0

これは私の最初の考えでしたが、これが正しい方法であるかどうかは確信が持てませんでした。それはちょうど...汚い感じ。 –

+0

これは、これが古典的なSQLプログラミングのやや不可解な難点の1つであることに完全に同意します。 – egrunin

1

IN句の項目数が十分多い場合は、一時表を使用することをお勧めします。まず値を挿入してから一時表に結合するか、SELECTの副問合せソースとして使用します。

このCodeProject articleは一時テーブルの使用について説明しています。しかし、あなたのケースのために要約する:

CREATE TABLE #TempQueryList(Item varchar(300)) 

// in your app code: 
insert into #TempQueryList values (@item); -- use BIND variable 
insert into #TempQueryList values (@item); -- use BIND variable 
... 
insert into #TempQueryList values (@item); -- use BIND variable 

// then your query becomes: 
SELECT 
    ID, Name 
FROM 
    MyTable 
WHERE 
    SomeValue IN (SELECT Item FROM #TempQueryList) 
1

(egruninが示したように)あなたがサブクエリでそれを行うことができれば、それが最も簡単かつ最速のです。それができない場合(つまり、値のリストがあれば)、表の値のパラメーターを調べることができます。

This questionには多少の興味があります。ここで

2

トピックについては、一連の記事で詳しく説明しています。

あなたはTable Value Parameterを使用して、最初の記事で推奨されるアプローチを開始する必要があります。また、MSDNの使用の記事を参照してください。Table-Valued Parameters in SQL Server 2008 (ADO.NET)

void SelectValuesOfInterest(IEnumerable<SqlDataRecord> valuesOfInterest) 
SqlCommand cmd = new SqlCommand(@" SELECT 
     ID, Name 
    FROM 
     MyTable 
    WHERE 
     SomeValue IN (SELECT value FROM @tableValueParameter);" 
, connection); 
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue(
    "@tableValueParameter", valuesOfInterest); 
tvpParam.SqlDbType = SqlDbType.Structured; 
tvpParam.TypeName = "dbo.MyTVPType"; 
using (SqlDataReader rdr = cmd.ExecuteReader()) 
{ 
while rdr.Read() {...} 
} 
} 
+0

SQL Serverのバージョンについての記述はありません。彼はSQL 2008の必要性を追加したいかもしれません。 –

1

私はtable value parameterを使用すると思います。アクセスできるSQLサーバーのバージョンによっては、データテーブル全体をストアドプロシージャに渡して、通常のテーブルと同様にクエリを実行することができます。

基本的には、あなたのリストを含むC#でテーブルを作成します。これをパラメータとしてストアドプロシージャに渡します。 procでは、MyTableと、渡したパラメータの間で内部結合を行い、必要な結果を得ることができます。

+0

これは正しい使用方法のようです。その方向で私を指摘してくれてありがとう、私はこれを考えなかった! –

関連する問題