go-mssqldb を用いたテーブル値パラメータ

テーブルバリューパラメータ(TVP)は、複数の構造化データをストアドプロシージャやパラメータ化されたクエリに渡すことを可能にします。 go-mssqldbドライバーはmssql.TVPタイプを通じてTVPをサポートしています。

強力に型付けされた行セットをストアドプロシージャやコマンドに渡し、列レベルの構造を保持する必要がある場合はTVPを使いましょう。 宛先テーブルへの最もスループットの高い経路には 、バルク操作を使用します。 ペイロードがネストされているか、すでにアプリケーション層がJSON形の場合は、 JSONやXMLデータを使いましょう。

前提条件

ユーザー定義のテーブル型と、それを受け付けるストアドプロシージャを作成します:

CREATE TYPE dbo.DepartmentType AS TABLE (
    Name NVARCHAR(50),
    GroupName NVARCHAR(50)
);
GO

CREATE PROCEDURE dbo.InsertDepartments
    @departments dbo.DepartmentType READONLY
AS
BEGIN
    INSERT INTO HumanResources.Department (Name, GroupName)
    SELECT Name, GroupName FROM @departments;
END;
GO

TVP行用のGo構造体を定義します

ユーザー定義のテーブルタイプの列に一致するGo構造体タイプを作成します:

type DepartmentRow struct {
    Name      string
    GroupName string
}

TVPをストアドプロシージャに渡す

型名と構造体のスライスを使った mssql.TVP の値を作成し、それをパラメータとして渡します。

import (
    "context"
    "database/sql"

    "github.com/microsoft/go-mssqldb"
)

func insertDepartments(ctx context.Context, db *sql.DB, departments []DepartmentRow) error {
    tvp := mssql.TVP{
        TypeName: "dbo.DepartmentType",
        Value:    departments,
    }

    _, err := db.ExecContext(ctx, "dbo.InsertDepartments",
        sql.Named("departments", tvp))
    return err
}

関数を呼び出します:

departments := []DepartmentRow{
    {Name: "Data Science", GroupName: "Research and Development"},
    {Name: "Cloud Ops", GroupName: "Information Technology"},
    {Name: "Developer Relations", GroupName: "Sales and Marketing"},
}
err := insertDepartments(ctx, db, departments)

列とフィールドのマッピング

ドライバーは、TVP の列を名前ではなく位置に基づいて構造体のフィールドにマッピングします。 最初の構造体フィールドはテーブルタイプの最初の列に、2番目のフィールドは2列目、3番目のフィールドは3番目の列にマッピングされ、このようにテーブルタイプのすべての列に対して対応します。

列をスキップするには、structタグを使うことはできません。 ユーザー定義テーブル型の列順に合わせて、Go 型を並べ替えるか再構成してください。

サポートされているフィールドの種類

TVPの構造体フィールドは通常のパラメータと同じGoタイプをサポートしています:

囲碁フィールドタイプ SQL Server カラムタイプ
string nvarchar
mssql.VarChar varchar
int64int32int16int8 bigintintsmallinttinyint
float64float32 floatreal
bool bit
time.Time datetimeoffset
[]byte varbinary
mssql.UniqueIdentifier uniqueidentifier

空のTVP

空のスライスを渡してもいいですよ。 ストアドプロシージャは行がゼロのテーブルを受け取ります:

tvp := mssql.TVP{
    TypeName: "dbo.DepartmentType",
    Value:    []DepartmentRow{},
}

スキーマ限定型名

TypeName ユーザー定義のテーブルタイプ名でなければなりません(宛先のテーブル名やストアドプロシージャ名ではありません)。 テーブル型がデフォルトでないスキーマであれば、 TypeNameにスキーマを含めてください。

tvp := mssql.TVP{
    TypeName: "HumanResources.DepartmentType",
    Value:    departments,
}