Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Ovladač go-mssqldb podporuje volání uložených procedur s vstupními parametry, výstupními parametry a návratovými stavovými hodnotami. Tento článek se zabývá běžnými vzory.
Většina úryvků v tomto článku předpokládá, že obvyklá konfigurace database/sql je už nastavena, kde je database/sql importováno jako sql, je k dispozici hodnota ctx a db je inicializováno. Fragmenty kódu obsahují bloky importů pouze tehdy, když přidávají další balíčky, například context, fmt, log, os nebo github.com/microsoft/go-mssqldb. Když blok kódu záměrně pokračuje ve stejném příkladu, použijte = pro hodnoty, které již byly v daném příkladu deklarovány; použijte := pro nové deklarace ve samostatných úryvcích.
Volání uložené procedury
Použijte ExecContext nebo QueryContext přímo s názvem postupu:
_, err := db.ExecContext(ctx, "dbo.uspGetEmployeeManagers",
sql.Named("BusinessEntityID", 6))
Preferujte název procedury plus parametry pro běžné volání procedur. Explicitní řetězec EXECUTE ... používejte pouze tehdy, když potřebujete volání vložit do větší dávky jazyka Transact-SQL (T-SQL) nebo když potřebujete použít syntaxi, kterou nelze vyjádřit pomocí parametrů sql.Named.
Výstupní parametry
Použijte sql.Named s sql.Out k přijímání hodnot výstupních parametrů:
import (
"context"
"database/sql"
"fmt"
"log"
)
ctx := context.Background()
var employeeCount int64
_, err := db.ExecContext(ctx, "dbo.GetEmployeeCount",
sql.Named("count", sql.Out{Dest: &employeeCount}))
if err != nil {
log.Fatal(err)
}
fmt.Println("Employee count:", employeeCount)
Odpovídající postup T-SQL:
CREATE PROCEDURE dbo.GetEmployeeCount
@count INT OUTPUT
AS
BEGIN
SELECT @count = COUNT(*) FROM HumanResources.Employee;
END;
Vstupní/výstupní parametry
Pro parametry, které jsou zároveň vstupem i výstupem, nastavte In: true na sql.Out struktuře:
var result int64 = 10
_, err := db.ExecContext(ctx, "dbo.DoubleValue",
sql.Named("value", sql.Out{Dest: &result, In: true}))
if err != nil {
log.Fatal(err)
}
fmt.Println("Doubled:", result)
Stav vrácení
Pomocí mssql.ReturnStatus zachytíte celočíselnou návratovou hodnotu uložené procedury. Tento příklad používá postup AdventureWorks dbo.uspGetEmployeeManagers :
import (
"database/sql"
"fmt"
"log"
mssql "github.com/microsoft/go-mssqldb"
)
var returnStatus mssql.ReturnStatus
rows, err := db.QueryContext(ctx, "dbo.uspGetEmployeeManagers",
sql.Named("BusinessEntityID", 6),
&returnStatus)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
fmt.Println("Return status:", returnStatus)
ReturnStatusFunguje s ExecContext a QueryContext, ale ne s QueryRowContext.
Můžete kombinovat ReturnStatus s parametry postupu. Tento příklad pokračuje v předchozím příkladu, takže znovu použije mssql import ukázaný dříve a použije postup AdventureWorks dbo.uspGetEmployeeManagers :
var returnStatus mssql.ReturnStatus
rows, err := db.QueryContext(ctx, "dbo.uspGetEmployeeManagers",
sql.Named("BusinessEntityID", 6),
&returnStatus)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
Sady výsledků z uložených procedur
Pokud uložená procedura vrací množiny výsledků, použijte QueryContext:
rows, err := db.QueryContext(ctx, "dbo.uspGetEmployeeManagers", sql.Named("BusinessEntityID", 6))
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var reportingLevel int
var employeeID int
var employeeFirstName string
var employeeLastName string
var organizationNode string
var managerFirstName string
var managerLastName string
if err := rows.Scan(&reportingLevel, &employeeID, &employeeFirstName, &employeeLastName, &organizationNode, &managerFirstName, &managerLastName); err != nil {
log.Fatal(err)
}
fmt.Printf("Level %d: %d %s %s (manager: %s %s)\n",
reportingLevel, employeeID, employeeFirstName, employeeLastName, managerFirstName, managerLastName)
_ = organizationNode
}
Pro procedury, které vracejí více sad výsledků, použijte rows.NextResultSet(). Pro více informací viz Dotazy a výpisy.
Přečtěte všechny řádky před použitím výstupních parametrů nebo vrácení stavu
SQL Server odesílá výstupní parametry a vrací stavové hodnoty po dokončení výsledkové sady. Pokud přečtete výstupní proměnnou před konzumací všech řádků, hodnota může být stále neúplná.
Tento příklad navazuje na předchozí a znovu používá mssql import uvedený dříve.
Nevytiskne data řádku. Smyčka spotřebovává pouze výslednou množinu, takže returnStatus je dostupná po dokončení dotazu.
var returnStatus mssql.ReturnStatus
rows, err := db.QueryContext(ctx, "dbo.uspGetEmployeeManagers",
sql.Named("BusinessEntityID", 6),
&returnStatus)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var reportingLevel int
var employeeID int
var employeeFirstName string
var employeeLastName string
var organizationNode string
var managerFirstName string
var managerLastName string
if err := rows.Scan(&reportingLevel, &employeeID, &employeeFirstName, &employeeLastName, &organizationNode, &managerFirstName, &managerLastName); err != nil {
log.Fatal(err)
}
_ = organizationNode
_ = managerFirstName
_ = managerLastName
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
fmt.Println("Return status:", returnStatus)
Použijte ExecContext, když procedura nevrací řádky. Pokud procedura vrací řádky, počkejte, až budou všechny řádky a sady výsledků spotřebovány, než přečtete výstupní parametry nebo vrátíte stav.
Dočasné tabulky a uložené procedury
Když vytvoříte dočasnou tabulku a pak ji dotazujete v samostatných voláních, operace mohou běžet na různých spojích z poolu. Protože dočasné tabulky jsou zaměřeny na jedno spojení, druhé volání nemusí tabulku vidět.
Pro práci s dočasnými tabulkami použijte přístup s jedním připojením:
conn, err := db.Conn(ctx)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
_, err = conn.ExecContext(ctx, "CREATE TABLE #TempItems (Id INT, Name NVARCHAR(50))")
if err != nil {
log.Fatal(err)
}
_, err = conn.ExecContext(ctx, "INSERT INTO #TempItems VALUES (1, N'Item A')")
if err != nil {
log.Fatal(err)
}
rows, err := conn.QueryContext(ctx, "SELECT * FROM #TempItems")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
Alternativně lze operace zabalit do transakce, která je automaticky připne ke stejnému spojení.
Zachycování zpráv PRINT a RAISERROR
Příkazy SQL Serveru PRINT a RAISERROR se závažností 0–10 generují informační zprávy, které nejsou vraceny jako chyby jazyka Go. Chcete-li tyto zprávy zachytit, povolte parametr připojení log pomocí příznaku 2 (zprávy):
sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&log=2
Při zapnutí logování ovladač zapisuje PRINT výstupní a nízkozávažné RAISERROR zprávy do standardního log balíčku Go. Pro jejich programové zachycení nastavte před otevřením spojení vlastní logger:
import (
"database/sql"
"log"
"os"
mssql "github.com/microsoft/go-mssqldb"
)
// Direct driver messages to a custom logger.
mssql.SetLogger(log.New(os.Stdout, "mssql: ", log.LstdFlags))
db, err := sql.Open("sqlserver",
"sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&log=2")
Pak jakákoli uložená procedura, která používá PRINT nebo RAISERROR(..., 0, 1) posílá své zprávy do vašeho loggeru.
Note
RAISERROR s závažností 11 nebo vyšší vytvoří chybu Go, kterou lze zvládnout běžnou kontrolou chyb. Pouze zprávy závažnosti 0–10 vyžadují zachycení parametru log .
Pro více informací o logovacích příznakech a programovém zachycování logů viz Logování a diagnostika.