List<string> からデータベースを検索する - テーブル値パラメータ Table-Valued Parameters (TVP) を利用した検索

C#でテーブル値パラメータ (Table-Valued Parameters - TVP)を利用した検索のコードを紹介します。

概要

SQLで複数の値に一致する検索の場合には、IN演算子を利用すると検索できます。(IN演算子についてはこちらの記事を参照)

値の値が少ないうちは問題ないですが、プログラム等で、大量の値のリストが与えられた場合にはINを利用したクエリの大きさが大きくなることや、 SQLの作成が面倒になりjます。また、パフォーマンス面でもINに大量の候補がある場合には、IN演算子よりテーブル値パラメータ(TVP)のほうが速くなります。

この記事では、テーブル値パラメーターを作成して検索するコードを紹介します。

事前準備

テーブルの準備

今回は以下のテーブルを利用します。

ProductsF
idmodelnameclasscategoryprice
1C-XM01モーダンチェアホームチェア56000
2X-XD05ラージデスクオフィステーブル87000
3A-DA40ラウンドダイニングチェアホームチェア28000
4O-XX100ナチュラルオフィスオフィスチェア13800
5R-D400ラウンドダイニングテーブルホームテーブル128000
6R7000ウッドキャビネットオフィスその他32000
7B-200リネンベッドホームベッド184500
8B-250ホワイトダブルベッドホームベッド324850
9W-80ワーキングチェアオフィスチェア45000
10EG-10Xエルゴノミクスデスクオフィステーブル88500
11NC-208ナチュラルウッドチェアホームチェア128000

事前準備: テーブル値型の定義

はじめに、SQL Server 側でテーブル値型を定義します。
今回は、modelで検索することを想定しています。modelはNCHAR(64) で定義されていますので、以下のテーブル値型を作成するSQLを実行します。

CREATE TYPE dbo.ModelList AS TABLE
(
    Model NCHAR(256) PRIMARY KEY
);


SQLを実行すると、SQL Serverのデータベースにユーザー定義テーブル型が作成されます。 SQL Server Management Studio で確認する場合は、オブジェクトエクスプローラーでデータベースのノードを開き、 [プログラミング] > [種類] > [ユーザー適宜テーブル型] のノード内にテーブル定義の項目が表示されます。

List<string> からデータベースを検索する - テーブル値パラメータ Table-Valued Parameters (TVP) を利用した検索:画像1

プログラム

Windows Formアプリケーションを作成し、以下のプログラムを作成します。
List<string> からデータベースを検索する - テーブル値パラメータ Table-Valued Parameters (TVP) を利用した検索:画像2

UI

テキストボックスとボタンを1つ配置したフォーム作成します。

コード

using Microsoft.Data.SqlClient;
using static System.ComponentModel.Design.ObjectSelectorEditor;
using System.Windows.Forms;
using System.Data;

namespace TableValuedParametersQuery
{
  public partial class FormMain : Form
  {
    public FormMain()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      List<string> qList = new List<string>() { "X-XD05", "R-D400", "B-250", "NC-208" };

      string constr = @"Data Source=(DBホスト名またはIPアドレス);Initial Catalog=(データベース名);Connect Timeout=60;Persist Security Info=True;Encrypt=False;User ID=(DBユーザーID);Password=(DBパスワード)";

      using (SqlConnection con = new SqlConnection(constr)) {
        try {
          con.Open();
          string sqlstr = "SELECT * FROM ProductsF WHERE model IN(SELECT Model FROM @TVPParam)";
          SqlCommand com = new SqlCommand(sqlstr, con);

          // テーブル値型のデータを作成
          DataTable table = new DataTable();
          table.Columns.Add("Model", typeof(string));
          foreach (string q in qList) {
            table.Rows.Add(q);
          }

          // テーブル値パラメータを追加
          SqlParameter tvpParam = com.Parameters.AddWithValue("@TVPParam", table);
          tvpParam.SqlDbType = SqlDbType.Structured;
          tvpParam.TypeName = "dbo.ModelList";
          /*
          //AddWithValue を利用しない書式
          SqlParameter tvpParam = com.CreateParameter();
          tvpParam.ParameterName = "@TVPParam";
          tvpParam.SqlDbType = SqlDbType.Structured;
          tvpParam.Direction = ParameterDirection.Input;
          tvpParam.Value = table;
          tvpParam.TypeName = "dbo.ModelList";
          com.Parameters.Add(tvpParam);
          */

          //exec
          SqlDataReader sdr = com.ExecuteReader();

          while (sdr.Read() == true) {
            string model = (string)sdr["model"];
            string name = (string)sdr["name"];
            string category = (string)sdr["category"];
            decimal price = (decimal)sdr["price"];
            textBox1.Text += string.Format("{0} / {1} / {2} : {3:g} \r\n", model.Trim(), name.Trim(), category.Trim(), price);
          }
        }

        finally {
          con.Close();
        }
      }
    }
  }
}

解説

基本はこちらの記事で紹介している、SQL文を実行するプログラムと同様です。

SQL文は以下になります。IN演算子を利用し、サブクエリ(副問い合わせ)でユーザー定義テーブルの値が含まれているかを判定します。

string sqlstr = "SELECT * FROM ProductsF WHERE model IN(SELECT Model FROM @TVPParam)";


SqlCommand作成後に、テーブルパラメーターの作成をします。DataTableオブジェクトを作成し、 データベースのユーザー定義テーブル型の列名と同じ名前で、列を追加します。
Row.Addメソッドを呼び出し、検索したい値をDataTableオブジェクトに挿入します。

  DataTable table = new DataTable();
  table.Columns.Add("Model", typeof(string));
  foreach (string q in qList) {
    table.Rows.Add(q);
  }


SQLパラメーターの追加も基本はこちらの記事で紹介しているコードと同様です。
テーブルパラメータ型を利用する場合は、SqlDbTypeに SqlDbType.Structured を設定します。 また、TypeName にはユーザー定義テーブル型の名称を設定します。

  SqlParameter tvpParam = com.Parameters.AddWithValue("@TVPParam", table);
  tvpParam.SqlDbType = SqlDbType.Structured;
  tvpParam.TypeName = "dbo.ModelList";


AddWithValue を利用しない場合は以下の記述で動作します。

  SqlParameter tvpParam = com.CreateParameter();
  tvpParam.ParameterName = "@TVPParam";
  tvpParam.SqlDbType = SqlDbType.Structured;
  tvpParam.Direction = ParameterDirection.Input;
  tvpParam.Value = table;
  tvpParam.TypeName = "dbo.ModelList";
  com.Parameters.Add(tvpParam);


SQLクエリを実行して、結果を取得してテキストボックスに表示します。

  SqlDataReader sdr = com.ExecuteReader();

  while (sdr.Read() == true) {
    string model = (string)sdr["model"];
    string name = (string)sdr["name"];
    string category = (string)sdr["category"];
    decimal price = (decimal)sdr["price"];
    textBox1.Text += string.Format("{0} / {1} / {2} : {3:g} \r\n", model.Trim(), name.Trim(), category.Trim(), price);
  }

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。
List<string> からデータベースを検索する - テーブル値パラメータ Table-Valued Parameters (TVP) を利用した検索:画像3

[button1]をクリックします。データベースを検索した結果が表示されます。
プログラムで設定した、 "X-XD05", "R-D400", "B-250", "NC-208" の項目の情報がデータベースから検索できています。
List<string> からデータベースを検索する - テーブル値パラメータ Table-Valued Parameters (TVP) を利用した検索:画像4

テーブル値パラメータ (Table-Valued Parameters)を利用した検索を実装できました。

AuthorPortraitAlt
著者
iPentec.com の代表。ハードウェア、サーバー投資、管理などを担当。
Office 365やデータベースの記事なども担当。
作成日: 2024-12-29
Copyright © 1995–2025 iPentec all rights reserverd.