Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Table-valued parameters (TVP) enable you to pass multiple rows of structured data to a stored procedure or parameterized query. The go-mssqldb driver supports TVP through the mssql.TVP type.
Use TVPs when you need to pass a strongly typed rowset into a stored procedure or command and preserve column-level structure. For the highest-throughput path into a destination table, use Bulk operations. If your payload is nested or already JSON-shaped in the application layer, use JSON and XML data.
Prerequisites
Create a user-defined table type and a stored procedure that accepts it:
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
Define a Go struct for the TVP rows
Create a Go struct type that matches the columns in the user-defined table type:
type DepartmentRow struct {
Name string
GroupName string
}
Pass a TVP to a stored procedure
Create an mssql.TVP value with the type name and a slice of structs, then pass it as a parameter:
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
}
Call the function:
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)
Column-to-field mapping
The driver maps TVP columns to struct fields by position (not by name). The first struct field maps to the first column in the table type, the second field maps to the second column, the third field maps to the third column, and so on for all columns in the table type.
To skip a column, you can't use struct tags. Reorder or restructure your Go type to match the column order in the user-defined table type.
Supported field types
TVP struct fields support the same Go types as regular parameters:
| Go field type | SQL Server column type |
|---|---|
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 |
Empty TVP
You can pass an empty slice. The stored procedure receives a table with zero rows:
tvp := mssql.TVP{
TypeName: "dbo.DepartmentType",
Value: []DepartmentRow{},
}
Schema-qualified type name
TypeName must be the user-defined table type name (not the destination table name or stored procedure name). If the table type is in a non-default schema, include the schema in TypeName:
tvp := mssql.TVP{
TypeName: "HumanResources.DepartmentType",
Value: departments,
}