MyProductsというテーブルがあり、item1とitem2を返したいです。
SELECT item1, item2 from MyProducts
ただし、(C#から)渡した文字列配列でフィルタリングする必要があります。これは非常に大きなテーブルなので、「IN」ステートメントが出ています。joinステートメントを使用してこれを行うにはどうすればよいですか。ありがとう!
MyProductsというテーブルがあり、item1とitem2を返したいです。
SELECT item1, item2 from MyProducts
ただし、(C#から)渡した文字列配列でフィルタリングする必要があります。これは非常に大きなテーブルなので、「IN」ステートメントが出ています。joinステートメントを使用してこれを行うにはどうすればよいですか。ありがとう!
私はいつもこの方法が好きでした...
CREATE FUNCTION dbo.Split(@String varchar(max), @Delimiter char(1))
returns @temptable TABLE (Value varchar(max))
as
begin
declare @idx int
declare @slice varchar(max)
select @idx = 1
if len(@String)<1 or @String is null return
while @idx!= 0
begin
set @idx = charindex(@Delimiter,@String)
if @idx!=0
set @slice = left(@String,@idx - 1)
else
set @slice = @String
if(len(@slice)>0)
insert into @temptable(Items) values(@slice)
set @String = right(@String,len(@String) - @idx)
if len(@String) = 0 break
end
return
end
その後、これを行うことができます...
CREATE PROCEDURE MySp
@list varchar(max)
AS
SELECT <columns>
FROM <mytable> mt
INNER JOIN dbo.split(@list,',') s ON s.Value= my.Key
注:そこには多くの分割関数があるので、この特定の関数を使用する必要はありません。
SQL Server 2008を使用するときに使用した別の方法は、次のようなテーブルパラメーターを使用することです...
CREATE TYPE [dbo].[LookupTable] As Table
(
ID Int primary key
)
CREATE PROCEDURE [dbo].[SampleProcedure]
(
@idTable As [dbo].[LookupTable] Readonly
)
AS
BEGIN
SELECT <columns>
FROM <mytable> mt
INNER JOIN @idTable s ON s.Id= my.Key
END
この方法で、C#からSQLServerにパラメーターを渡します。
DataTable dataTable = new DataTable("SampleDataType");
dataTable.Columns.Add("Id", typeof(Int32));
foreach (var id in <mycollectionofids>)
dataTable.Rows.Add(id);
SqlParameter parameter = new SqlParameter();
parameter.ParameterName="@Id";
parameter.SqlDbType = System.Data.SqlDbType.Structured;
parameter.Value = dataTable;
command.Parameters.Add(parameter);
IN
ステートメントが「アウト」である理由はありません。最終的に、これはフィルタリングの完全に合理的な方法です。オプティマイザにさまざまなオプションについて心配させます。それは確かにMyProducts
大きいという事実によって影響を受けません。結合を追加すると、より多くの作業が行われます。ただし、「ヒット」の数や関連する作業が減少するわけではありません。たとえば、dapper でそれを行うには、次のようにします。
string[] filter = ...
var rows = connection.Query(
"select item1, item2 from MyProducts where SomeField in @filter",
new {filter});
またはLINQを使用:
string[] filter = ...
var rows = db.Products.Where(x => filter.Contains(x.SomeField));
1 つの解決策は、一時テーブルを作成して結合することです。一時テーブルは、結合する列にインデックスを持つことができます。