Parámetros con valores en tabla con go-mssqldb

Los parámetros con valores de tabla (TVP) te permiten pasar varias filas de datos estructurados a un procedimiento almacenado o consulta parametrizada. El go-mssqldb controlador soporta TVP a través del mssql.TVP tipo.

Utiliza TVPs cuando necesites pasar un conjunto de filas fuertemente tipado a un procedimiento almacenado o comando y conservar la estructura a nivel de columna. Para el camino de mayor rendimiento hacia una tabla de destino, utiliza operaciones en bloque. Si tu carga útil está anidada o ya tiene forma JSON en la capa de aplicación, usa datos JSON y XML.

Prerrequisitos

Crea un tipo de tabla definido por el usuario y un procedimiento almacenado que lo acepte:

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

Definir una estructura de Go para las filas del TVP

Crea un tipo de struct Go que coincida con las columnas del tipo de tabla definido por el usuario:

type DepartmentRow struct {
    Name      string
    GroupName string
}

Pasar un TVP a un procedimiento almacenado

Crea un mssql.TVP valor con el nombre del tipo y una porción de structs, y luego pásalo como parámetro:

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
}

Llama a la función:

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)

Mapeo columna-campo

El controlador asigna columnas TVP a campos estructurados por posición (no por nombre). El primer campo struct se asigna a la primera columna del tipo de tabla, el segundo campo a la segunda columna, el tercer campo a la tercera columna, y así sucesivamente para todas las columnas del tipo de tabla.

Para saltarte una columna, no puedes usar etiquetas estructuras. Reordena o reestructura tu tipo Go para que coincida con el orden de columnas en el tipo de tabla definido por el usuario.

Tipos de campo admitidos

Los campos de struct TVP soportan los mismos tipos de Go que los parámetros normales:

Tipo de campo de Go Tipo de columna en SQL Server
string nvarchar
mssql.VarChar varchar
int64, int32, , int16, int8 bigint, int, , smallint, tinyint
float64, float32 float, real
bool bit
time.Time datetimeoffset
[]byte varbinary
mssql.UniqueIdentifier uniqueidentifier

TVP vacío

Puedes pasar una porción vacía. El procedimiento almacenado recibe una tabla con cero filas:

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

Nombre de tipo cualificado por esquema

TypeName debe ser el nombre del tipo de tabla definido por el usuario (no el nombre de la tabla de destino ni el nombre del procedimiento almacenado). Si el tipo de tabla pertenece a un esquema no predeterminado, incluye el esquema en TypeName:

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