go-mssqldb Datentypabbildungen

Der Treiber go-mssqldb wandelt Go-Typen automatisch in SQL Server-Typen um, wenn man Parameter übergibt, und wandelt SQL Server-Typen beim Scannen der Ergebnisse wieder in Go-Typen um. Dieser Artikel dokumentiert die Standard-Konvertierungen und die treiberspezifischen Typen, die explizit gesteuert werden können.

Beispiele in diesem Artikel laufen gegen die AdventureWorks2025-Beispieldatenbank . Leseorientierte Beispiele fragen eingebaute Objekte wie Production.Product und Sales.vSalesPersonab. Schreiborientierte Beispiele zielen HumanResources.Department auf und Production.ProductCategory.

Gehe zu SQL Server Parameterabbildungen

Wenn Sie Werte als Abfrageparameter übergeben, wandelt der Treiber Go-Typen in SQL Server-Typen um:

Go-Type SQL Server-Typ Hinweise
string nvarchar Unicode-Zeichenkette. Verwendung mssql.VarChar für nicht-Unicode-Varchar.
[]byte varbinary Binäre Daten.
int64 bigint
float64 float 64-Bit-Float.
bool Bit
time.Time datetimeoffset Bewahrt die Zeitzonenverschiebung. Nutze mssql.DateTime1 sie für das Date-Time. mssql.DateTimeOffset Verwendung für explizite Offset-Kontrolle.
int32 int
int16 smallint
int8 tinyint
float32 real 32-Bit-Float.
mssql.TVP tabellenwertiger Parameter Siehe Tabellenwerte Parameter.

Fahrerspezifische Typen

Verwenden Sie diese Typen aus dem mssql Paket, wenn Sie explizite Kontrolle über den SQL Server-Typ benötigen:

Treibertyp SQL Server-Typ Beschreibung
mssql.VarChar varchar Kein Unicode-String. Wickle einen string Wert ein.
mssql.NVarCharMax nvarchar(max) Unicode-Zeichenkette.
mssql.VarCharMax varchar(max) Nicht Unicode-große Zeichenkette.
mssql.NChar nchar Unicode-String mit fester Länge. Wickle einen string Wert ein.
mssql.DateTime1 datetime Legacy-Datumszeit ohne Offset.
mssql.DateTimeOffset datetimeoffset Explizite Offset-Kontrolle.
mssql.NullDate date Nullierbarer, nur datierter Wert.
mssql.NullTime Zeit Nullierbarer Zeit-Only-Wert.
mssql.NullDateTime datetime2 Nullierbarer Datums- und Zeitwert ohne Zeitzonenumrechnung.
mssql.UniqueIdentifier uniqueidentifier GUID-Wert.
mssql.TVP Benutzerdefinierter Tabellentyp Tabellenwertige Parameterstruktur.

Verwenden Sie die nullablen Datums- und Uhrzeit-Helfertypen, wenn Sie SQL Server nur Datum- oder Zeit-Semantik benötigen und der Parameter oder das Scan-Ziel möglicherweise NULL ist.

Beispiel: Varchar vs. Nvarchar

Standardmäßig string werden die Parameter als nvarchargesendet. Stattdessen verwenden varchar :

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"))

Beispiel: Uniqueidentifier

Verwenden Sie den Typ mssql.UniqueIdentifier , um Spalten zu scannen uniqueidentifier :

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)

SQL Server to Go Ergebniszuordnungen

Wenn Sie die Ergebnisse abfragen, wandelt der Treiber SQL Server-Typen in Go-Typen um:

SQL Server-Typ Go-Type Hinweise
int, bigint, smallint, tinyint int64 Alle ganzzahligen Typen scannen nach int64. Zaubern Sie nach Bedarf.
schweben, echt float64
Dezimal-, Numerisch-, Geld-, Kleingeld-, []byte oder string Kein nativer Go-Dezimaltyp. Scannen Sie in string oder verwenden Sie eine Dezimalbibliothek von Drittanbietern.
Bit bool
Char, Varchar, Text string
nchar, nvarchar, ntext string
Binär,Varbinär, Bild []byte
Date, Datetime, Datetime2, Smalldatetime time.Time
datetimeoffset time.Time Zeitzonenversatz bleibt erhalten.
Zeit time.Time Die Date-Komponente ist 0001-01-01.
uniqueidentifier []byte oder mssql.UniqueIdentifier Scannt standardmäßig auf Rohbytes. mssql.UniqueIdentifier Verwendung für formatierte GUID-Ausgaben.
sql_variant interface{} Der konkrete Go-Typ hängt vom gespeicherten Wert des SQL Server ab.
xml string

Benannte Parameter

Verwenden sql.Named Sie, um benannte Parameter zu erstellen:

rows, err := db.QueryContext(ctx,
    "SELECT * FROM Sales.vSalesPerson WHERE CountryRegionName = @location AND FirstName = @name",
    sql.Named("location", "Australia"),
    sql.Named("name", "Jared"))

Hinweis

Positionsparameter (@p1, @p2) funktionieren ebenfalls. Der Treiber weist Ordinalnamen basierend auf der Reihenfolge der Argumente zu.

Handle NULL-Werte

SQL Server-Spalten, die NULL erlauben, erfordern eine spezielle Behandlung in Go. Das Standardpaket database/sql stellt für diesen Zweck nullbare Typen bereit.

SQL. Nulltypen

Verwenden sql.NullStringSie , sql.NullInt64, sql.NullFloat64, sql.NullBool, und sql.NullTime um Spalten zu handhaben, die NULL sein können. Für SQL Server Datum-, Uhrzeit- und Datumzeit2-Werte, die Sie von Gos time.Time Standardwerten getrennt halten möchten, verwenden mssql.NullDateSie , mssql.NullTime, und 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)
}

Pointerbasierte NULL-Handhabung

Verwenden Sie als Alternative zu sql.Null Typen Zeiger. Ein nil Zeiger repräsentiert 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

Die zeigerbasierte NULL-Behandlung ist prägnanter, aber sql.Null die Typen machen die NULL-Absicht in Strukturdefinitionen expliziter. Wählen Sie das Muster, das Ihr Team bevorzugt, und verwenden Sie es konsequent.

Senden Sie NULL-Werte als Parameter

Pass, nil um einen NULL-Wert als Parameter zu senden:

// Insert a row with a NULL Color.
_, err := db.ExecContext(ctx,
    "INSERT INTO Production.ProductCategory (Name) VALUES (@name)",
    sql.Named("name", "Custom Parts"))

Dezimal- und numerische Genauigkeit

SQL Server decimal und numeric -Typen unterstützen eine Präzision von bis zu 38 Ziffern. Go's float64 liefert nur etwa 15–16 signifikante Ziffern. Das Scannen hochpräziser Werte verursacht float64 einen stillen Präzisionsverlust.

Scannen auf die Saite

Der sicherste und einfachste Ansatz ist es, Spalten in zu scannendecimal/numeric/money/smallmoney, und dann mit einer präzisionssicheren Bibliothek zu konvertieren:string

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"

Für leistungsempfindliche Pfade kannst du direkt in []byte deine Dezimalbibliothek einscannen und diese parsen, um die Zuweisung von Strings zu reduzieren.

Verwenden Sie shopspring/dezimal für die Arithmetik

Die Bibliothek shopspring/decimal bietet dezimale Arithmetik mit beliebiger Genauigkeit:

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))

Achtung

Scanne money oder decimal spalte niemals in float64 den Punkt, an dem genaue Genauigkeit wichtig ist (Finanzberechnungen, Währung, Steuern). Verwenden Sie das exakt-Wert-Scannen (string oder []byte) mit shopspring/decimal oder cockroachdb/apd stattdessen.

Senden Sie Dezimalwerte als Parameter

Beim Senden von Dezimalwerten als Parameter verwenden string Sie, um einen Verlust der Float-Präzision zu vermeiden:

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.

Datums- und Uhrzeittypen

Zeit. Zeitabbildung

Der Fahrer ordnet Go's standardmäßig zutime.Time, wodurch der Zeitzonen-Offset datetimeoffset erhalten bleibt. Verwenden Sie treiberspezifische Typen für andere Date-Time-Formate:

Go-Wert SQL Server-Typ Wann verwenden?
time.Time datetimeoffset Standard. Benutze sie, wenn die Zeitzone wichtig ist.
mssql.DateTime1(t) datetime Legacy-Kolumnen, die keinen Offset unterstützen.
mssql.DateTimeOffset(t) datetimeoffset Explizite Offset-Kontrolle.

UTC Best Practice

Speichern der Zeiten in UTC und in der Anwendungsschicht in lokale Zeit umwandeln:

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))

Uniqueidentifier (GUID) Muster

SQL Server speichert uniqueidentifier Werte mit den ersten drei Gruppen in Little-Endian-Byte-Reihenfolge (auch bekannt als mixed-Endian- oder GUID-Byte-Ordnung). Wenn du eine Spalte uniqueidentifier in []bytescannst, stimmen die Rohbytes nicht mit der Standard-String-Darstellung überein. mssql.UniqueIdentifier Use instead, das die Byte-Order-Umwandlung automatisch übernimmt.

Scanne mit mssql. UniqueIdentifier

Standardmäßig uniqueidentifier scannen die Spalten auf []byte. Verwendung mssql.UniqueIdentifier für formatierte GUID-Zeichenfolgen:

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"

Erstellen und senden Sie GUIDs

Auf dem Server verwenden NEWID() oder in Go generieren:

// 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)

Client-seitige Generierung mit dem google/uuid Paket:

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"))

Checkliste zur Typabbildung

Szenario Empfohlener Ansatz
Nullierbare Spalten Verwenden sql.NullStringSie , sql.NullInt64, sql.NullFloat64, , sql.NullBool, sql.NullTime, oder Zeigertypen.
Finanzielle/dezimale Werte Scanne zu, stringverwenden shopspring/decimal Sie für die Rechentechnik.
Daten mit Zeitzonen Verwenden time.Time (standardmäßig zugeordnet datetimeoffset ).
Legacy-Datumszeit-Spalten Verwenden mssql.DateTime1 Sie beim Senden von Parametern.
GUIDs Scanne mit mssql.UniqueIdentifier für formatierte Ausgaben.
Nicht-Unicode-Zeichenketten Nutze sie, mssql.VarChar um implizite nvarchar Umwandlung zu vermeiden.
JSON-Spalten Scanne auf string, unmarshal mit encoding/json. Siehe JSON- und XML-Daten.
XML-Spalten Scanne auf string, unmarshal mit encoding/xml. Siehe JSON- und XML-Daten.