Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Il go-mssqldb driver converte automaticamente i tipi Go in tipi SQL Server quando si passano i parametri, e riconverte i tipi SQL Server in tipi Go quando si scansionano i risultati. Questo articolo documenta le conversioni predefinite e i tipi specifici per driver disponibili per un controllo esplicito.
Gli esempi in questo articolo vengono confrontati con il database di esempio AdventureWorks2025 . Esempi orientati alla lettura interrogano oggetti integrati come Production.Product e Sales.vSalesPerson. Gli esempi orientati alla scrittura mirano HumanResources.Department a .Production.ProductCategory
Vai su SQL Server parameter mappings
Quando passi valori come parametri di query, il driver converte i tipi Go in tipi SQL Server:
| Tipo Go | Tipo SQL Server | Note |
|---|---|---|
string |
nvarchar | Stringa Unicode. Usa mssql.VarChar per varchar non-Unicode. |
[]byte |
varbinary | Dati binari. |
int64 |
bigint | |
float64 |
float | Float a 64 bit. |
bool |
pezzo | |
time.Time |
datetimeoffset | Preserva lo spostamento del fuso orario. Usa mssql.DateTime1 per l'appuntamento. Usare mssql.DateTimeOffset per un controllo esplicito dello spostamento. |
int32 |
int | |
int16 |
smallint | |
int8 |
tinyint | |
float32 |
real | Flottante a 32 bit. |
mssql.TVP |
Parametro con valori di tipo tabella | Vedi Parametri a valori della tabella. |
Tipi specifici per driver
Usa questi tipi dal mssql pacchetto quando hai bisogno di un controllo esplicito sul tipo SQL Server:
| Tipo di driver | Tipo SQL Server | Description |
|---|---|---|
mssql.VarChar |
varchar | Stringa non Unicode. Avvolgi un string valore. |
mssql.NVarCharMax |
nvarchar(max) | Stringa grande Unicode. |
mssql.VarCharMax |
varchar(max) | Stringa grande non Unicode. |
mssql.NChar |
nchar | Stringa Unicode a lunghezza fissa. Avvolgi un string valore. |
mssql.DateTime1 |
datetime | Datatime legacy senza offset. |
mssql.DateTimeOffset |
datetimeoffset | Controllo esplicito dello spostamento. |
mssql.NullDate |
date | Valore solo data nullabile. |
mssql.NullTime |
time | Valore solo temporale nullabile. |
mssql.NullDateTime |
datetime2 | Valore di data e ora nullabile senza conversione di fuso orario. |
mssql.UniqueIdentifier |
uniqueidentifier | Valore GUID. |
mssql.TVP |
Tipo di tabella definito dall'utente | Parametro a valori di tabella struct. |
Usa i tipi di aiuto data e ora nullabili quando hai bisogno di semantica solo data o solo tempo di SQL Server e il parametro o la destinazione di scansione potrebbero essere NULL.
Esempio: varchar vs. nvarchar
Di default, i string parametri vengono inviati come nvarchar. Da usare varchar invece:
import "github.com/microsoft/go-mssqldb"
// Sends as nvarchar (default)
db.QueryContext(ctx, "SELECT * FROM Production.Product WHERE Name = @p1", "Adjustable Race")
// Sends as varchar
db.QueryContext(ctx, "SELECT * FROM Production.Product WHERE Name = @p1", mssql.VarChar("Adjustable Race"))
Esempio: unicidentificatore
Usa il mssql.UniqueIdentifier tipo per scansionare uniqueidentifier le colonne:
import "github.com/microsoft/go-mssqldb"
var id mssql.UniqueIdentifier
err := db.QueryRowContext(ctx, "SELECT rowguid FROM Production.Product WHERE Name = @p1",
sql.Named("p1", "Adjustable Race")).Scan(&id)
Mappaggi dei risultati di SQL Server to Go
Quando scansioni i risultati delle query, il driver converte i tipi di SQL Server in tipi Go:
| Tipo SQL Server | Tipo Go | Note |
|---|---|---|
| int, bigint, smallint,tinyint | int64 |
Tutti i tipi di interi scansionano in int64. Invasa il congedo secondo necessità. |
| float, reale | float64 |
|
| decimale, numerico, denaro, piccolo denaro |
[]byte oppure string |
Nessun tipo decimale nativo Go. Scansiona o string usa una libreria decimale di terze parti. |
| pezzo | bool |
|
| Char, Varchar, testo | string |
|
| nchar, nvarchar, ntext | string |
|
| binario, varbinario, immagine | []byte |
|
| data, datatime, datetime2, smalldatetime | time.Time |
|
| datetimeoffset | time.Time |
Lo sfasamento del fuso orario viene mantenuto. |
| time | time.Time |
La componente della data è 0001-01-01. |
| uniqueidentifier |
[]byte oppure mssql.UniqueIdentifier |
Scansiona in byte raw di default. Da usare mssql.UniqueIdentifier per output GUID formattato. |
| sql_variant | interface{} |
Il tipo di Go in concreto dipende dal valore memorizzato di SQL Server. |
| xml | string |
Parametri denominati
Usare sql.Named per creare parametri nominati:
rows, err := db.QueryContext(ctx,
"SELECT * FROM Sales.vSalesPerson WHERE CountryRegionName = @location AND FirstName = @name",
sql.Named("location", "Australia"),
sql.Named("name", "Jared"))
Note
Anche i parametri posizionali (@p1, @p2) funzionano. Il driver assegna nomi ordinali in base all'ordine degli argomenti.
Gestire i valori NULL
Le colonne di SQL Server che permettono NULL richiedono una gestione speciale in Go. Il pacchetto standard database/sql fornisce tipi nullabili a questo scopo.
SQL. Tipi nulli
Usare sql.NullString, sql.NullInt64, sql.NullFloat64, sql.NullBool, e sql.NullTime per gestire colonne che possono essere NULL. Per i valori di data, ora e datetime2 di SQL Server che vuoi mantenere separati dai valori predefiniti di time.Time Go, usa mssql.NullDate, mssql.NullTime, e mssql.NullDateTime:
var name sql.NullString
var color sql.NullString
var weight sql.NullFloat64
var sellStartDate sql.NullTime
var sellEndDate sql.NullTime
err := db.QueryRowContext(ctx,
"SELECT Name, Color, Weight, SellStartDate, SellEndDate FROM Production.Product WHERE ProductID = @id",
sql.Named("id", 1)).Scan(&name, &color, &weight, &sellStartDate, &sellEndDate)
if err != nil {
log.Fatal(err)
}
if name.Valid {
fmt.Println("Name:", name.String)
} else {
fmt.Println("Name: NULL")
}
if weight.Valid {
fmt.Printf("Weight: %.2f\n", weight.Float64)
}
Gestione NULL basata su puntatore
Come alternativa ai sql.Null tipi, usa i puntatori. Un nil puntatore rappresenta NULL:
var name *string
var color *string
err := db.QueryRowContext(ctx,
"SELECT Name, Color FROM Production.Product WHERE ProductID = @id",
sql.Named("id", 1)).Scan(&name, &color)
if name != nil {
fmt.Println("Name:", *name)
} else {
fmt.Println("Name: NULL")
}
Tip
La gestione NULL basata su pointer è più concisa, ma sql.Null i tipi rendono l'intento NULL più esplicito nelle definizioni delle struct. Scegli il pattern che la tua squadra preferisce e usalo con costanza.
Invia valori NULL come parametri
Pass nil per inviare un valore NULL come parametro:
// Insert a row with a NULL Color.
_, err := db.ExecContext(ctx,
"INSERT INTO Production.ProductCategory (Name) VALUES (@name)",
sql.Named("name", "Custom Parts"))
Precisione decimale e numerica
I SQL Server decimal e numeric i tipi supportano fino a 38 cifre di precisione. Go float64 fornisce solo circa 15-16 cifre significative. Scansionare valori float64 ad alta precisione provoca perdita di precisione silenziosa.
Scansione a stringa
L'approccio più sicuro e semplice è scansionare decimal/numeric/money/smallmoney le colonne in string, poi convertire con una libreria sicura per precisione:
var priceStr string
err := db.QueryRowContext(ctx,
"SELECT ListPrice FROM Production.Product WHERE ProductID = @id",
sql.Named("id", 1)).Scan(&priceStr)
if err != nil {
log.Fatal(err)
}
fmt.Println("Price:", priceStr) // "12345.678901234567890"
Per percorsi sensibili alle prestazioni, puoi scansionare e []byte parizzare direttamente con la tua libreria decimale per ridurre le allocazioni di stringhe.
Usa shopspring/decimal per l'aritmetica
La shopspring/decimal libreria fornisce aritmetica decimale di precisione arbitraria:
import "github.com/shopspring/decimal"
var priceStr string
err := db.QueryRowContext(ctx,
"SELECT ListPrice FROM Production.Product WHERE ProductID = @id",
sql.Named("id", 1)).Scan(&priceStr)
if err != nil {
log.Fatal(err)
}
price, err := decimal.NewFromString(priceStr)
if err != nil {
log.Fatal(err)
}
tax := price.Mul(decimal.NewFromFloat(0.08))
total := price.Add(tax)
fmt.Println("Total:", total.StringFixed(2))
Attenzione
Non scansionare money mai le decimal colonne quando float64 la precisione esatta conta (calcoli finanziari, valuta, tasse). Usa la scansione a valore esatto (string o []byte) con shopspring/decimal o cockroachdb/apd invece.
Inviare valori decimali come parametri
Quando si inviano valori decimali come parametri, si usa string per evitare la perdita di precisione del float:
price := "12345.678901234567890"
_, err := db.ExecContext(ctx,
"UPDATE Production.Product SET ListPrice = @price WHERE ProductID = @id",
sql.Named("price", price),
sql.Named("id", 1)) // String is converted to decimal by SQL Server.
Tipi di data e ora
tempo. Mappatura temporale
Il driver mappa di default Go time.Time a datetimeoffset Go a , il che preserva lo offset del fuso orario. Usa tipi specifici per driver per altri formati di datetime:
| Valore Go | Tipo SQL Server | Quando utilizzare |
|---|---|---|
time.Time |
datetimeoffset |
Predefinito Usalo quando il fuso orario conta. |
mssql.DateTime1(t) |
datetime |
Colonne legacy che non supportano l'offset. |
mssql.DateTimeOffset(t) |
datetimeoffset |
Controllo esplicito dello spostamento. |
Migliori pratiche UTC
Memorizza i tempi in UTC e converti in ora locale nel livello applicativo:
now := time.Now().UTC()
_, err := db.ExecContext(ctx,
"INSERT INTO Production.ScrapReason (Name, ModifiedDate) VALUES (@name, @modified)",
sql.Named("name", "Operator error"),
sql.Named("modified", now))
Pattern univoci (GUID)
SQL Server memorizza uniqueidentifier i valori con i primi tre gruppi in ordine little-endian dei byte (noto anche come ordine mixed-endian o GUID). Se scansioni una uniqueidentifier colonna in []byte, i byte grezzi non corrispondono alla rappresentazione standard della stringa. Usa mssql.UniqueIdentifier invece, che gestisce automaticamente la conversione dell'ordine dei byte.
Scansiona con mssql. UnicoIdentificatore
Di default, uniqueidentifier le colonne scansionano verso []byte. Uso mssql.UniqueIdentifier per stringhe GUID formattate:
var id mssql.UniqueIdentifier
err := db.QueryRowContext(ctx,
"SELECT rowguid FROM Production.Product WHERE Name = @name",
sql.Named("name", "Adjustable Race")).Scan(&id)
if err != nil {
log.Fatal(err)
}
fmt.Println("ID:", id) // "6F9619FF-8B86-D011-B42D-00C04FC964FF"
Generare e inviare GUID
Utilizzare NEWID() sul server o generare in Go:
// Server-side generation
var newID mssql.UniqueIdentifier
err := db.QueryRowContext(ctx,
"INSERT INTO Production.ProductCategory (Name) OUTPUT INSERTED.rowguid VALUES (@name)",
sql.Named("name", "Custom Parts")).Scan(&newID)
Generazione lato client con il google/uuid package:
import "github.com/google/uuid"
id := mssql.UniqueIdentifier(uuid.New())
_, err := db.ExecContext(ctx,
"UPDATE Production.ProductCategory SET rowguid = @id WHERE Name = @name",
sql.Named("id", id),
sql.Named("name", "Custom Parts"))
Lista di controllo per la mappatura dei tipi
| Scenario | Approccio consigliato |
|---|---|
| Colonne nullabili | Usa sql.NullString, sql.NullInt64, sql.NullFloat64, sql.NullBool, sql.NullTime, o tipi di puntatori. |
| Valori finanziari/decimali | Scansiona in string, usa shopspring/decimal per l'aritmetica. |
| Date con fusi orari | Usa time.Time (mappa a datetimeoffset di default). |
| Colonne datatime ereditarie | Usare mssql.DateTime1 quando invio parametri. |
| GUID | Scansiona con mssql.UniqueIdentifier per l'output formattato. |
| Stringhe non Unicode | Usalo mssql.VarChar per evitare conversioni implicite nvarchar . |
| Colonne JSON | Scansiona per string, smaschera con encoding/json. Vedi dati JSON e XML. |
| Colonne XML | Scansiona per string, smaschera con encoding/xml. Vedi dati JSON e XML. |