Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
SQL Server, JSON ve XML veri için yerleşik destek sunar. Bu makale, sürücünün Go yapıları ile SQL Server arasında JSON ve XML verilerini sorgulamak, eklemek ve dönüştürmek için nasıl kullanılacağını go-mssqldb gösterir.
Bu makaledeki örnekler AdventureWorks2025 örnek veritabanıyla karşılaştırılıyor. Okuma odaklı örnekler, Sales.vSalesPerson ve Sales.SalesOrderHeader gibi yerleşik nesneleri sorgular. Yazma odaklı örnekler, HumanResources.Department içine satır eklemek için OPENJSON ve XML .nodes() kullanır.
Çoğu kod parçacığı, ctx ve db'in zaten başlatılmış olduğunu varsayar. Bu kurulum desenini kullanabilirsiniz:
import (
"context"
"database/sql"
"log"
"time"
_ "github.com/microsoft/go-mssqldb"
)
db, err := sql.Open("sqlserver", "sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&encrypt=true&TrustServerCertificate=true")
if err != nil {
log.Fatal(err)
}
defer db.Close()
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
JSON verileri
Sorgu sonuçlarını FOR JSON ile JSON olarak alma
Sorgu sonuçlarını JSON dizisi olarak döndürmek için kullanılır FOR JSON PATH :
var jsonResult string
err := db.QueryRowContext(ctx,
"SELECT BusinessEntityID AS Id, FirstName + ' ' + LastName AS Name, CountryRegionName AS Department FROM Sales.vSalesPerson WHERE CountryRegionName = @dept FOR JSON PATH",
sql.Named("dept", "United States")).Scan(&jsonResult)
if err != nil {
log.Fatal(err)
}
fmt.Println(jsonResult)
Note
SQL Server, daha büyük yükler için birden fazla satır üzerinden çıktı döndürebilirFOR JSON. Daha büyük sonuçları güvenilir şekilde desteklemek istiyorsanız, geri dönen tüm satırları okuyun ve birleştirin.
Büyük JSON sonuçlarını yönetin bkz.
Büyük JSON sonuçlarını yönetin
SQL Server JSON çıktısını birden fazla satırda döndürdüğünde, parçaları birleştirin, sonra sonucu yayından çıkarın veya yazdırın:
import "strings"
func queryJSON(ctx context.Context, db *sql.DB, query string, args ...any) (string, error) {
rows, err := db.QueryContext(ctx, query, args...)
if err != nil {
return "", err
}
defer rows.Close()
var sb strings.Builder
for rows.Next() {
var chunk string
if err := rows.Scan(&chunk); err != nil {
return "", err
}
sb.WriteString(chunk)
}
if err := rows.Err(); err != nil {
return "", err
}
return sb.String(), nil
}
Kullanım:
jsonStr, err := queryJSON(ctx, db,
"SELECT BusinessEntityID AS Id, FirstName + ' ' + LastName AS Name, CountryRegionName AS Department FROM Sales.vSalesPerson FOR JSON PATH")
if err != nil {
log.Fatal(err)
}
JSON sonuçlarını Go struct’larına ayrıştırma
SQL Server sonuçlarını doğrudan Go türlerine deserialize etmek için FOR JSON ile encoding/json’i birleştirin:
import "encoding/json"
type Employee struct {
ID int `json:"Id"`
Name string `json:"Name"`
Department string `json:"Department"`
}
func getEmployees(ctx context.Context, db *sql.DB, dept string) ([]Employee, error) {
var jsonStr string
err := db.QueryRowContext(ctx,
"SELECT BusinessEntityID AS Id, FirstName + ' ' + LastName AS Name, CountryRegionName AS Department FROM Sales.vSalesPerson WHERE CountryRegionName = @dept FOR JSON PATH",
sql.Named("dept", dept)).Scan(&jsonStr)
if err != nil {
return nil, err
}
var employees []Employee
if err := json.Unmarshal([]byte(jsonStr), &employees); err != nil {
return nil, err
}
return employees, nil
}
FOR JSON PATH ile iç içe JSON
Sütun aliaslarında nokta gösterimi kullanarak iç içe JSON yapıları oluşturun:
var jsonResult string
err := db.QueryRowContext(ctx, `
SELECT
soh.SalesOrderID AS [Id],
soh.OrderDate AS [OrderDate],
CONCAT(pp.FirstName, ' ', pp.LastName) AS [Customer.Name],
ea.EmailAddress AS [Customer.Email],
soh.TotalDue AS [Total]
FROM Sales.SalesOrderHeader AS soh
JOIN Sales.Customer AS c ON soh.CustomerID = c.CustomerID
LEFT JOIN Person.Person AS pp ON c.PersonID = pp.BusinessEntityID
LEFT JOIN Person.EmailAddress AS ea ON pp.BusinessEntityID = ea.BusinessEntityID
WHERE soh.SalesOrderID = @id
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER`,
sql.Named("id", 43659)).Scan(&jsonResult)
Sonuç:
{"Id":43659,"OrderDate":"2022-05-30T00:00:00","Customer":{"Name":"James Hendergart","Email":"james9@adventure-works.com"},"Total":23153.2339}
JSON'u SQL Server'da OPENJSON ile parse
OPENJSON Sunucu tarafında bir JSON diziyi satır parçalamak için kullanılır:
jsonData := `[
{"Name": "Alice", "Department": "Engineering"},
{"Name": "Bob", "Department": "Marketing"}
]`
rows, err := db.QueryContext(ctx, `
SELECT Name, Department
FROM OPENJSON(@json)
WITH (
Name NVARCHAR(100) '$.Name',
Department NVARCHAR(100) '$.Department'
)`, sql.Named("json", jsonData))
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var name, dept string
if err := rows.Scan(&name, &dept); err != nil {
log.Fatal(err)
}
fmt.Printf("%s - %s\n", name, dept)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
JSON verilerini parametre olarak ekle
Bir Go yapısını JSON dizisi olarak bir saklanan prosedüre gönderin veya OPENJSON:
type OrderItem struct {
ProductID int `json:"productId"`
Quantity int `json:"quantity"`
Price float64 `json:"price"`
}
func sendJSONPayload(ctx context.Context, db *sql.DB, metadata map[string]any) error {
jsonBytes, err := json.Marshal(metadata)
if err != nil {
return err
}
// Pass JSON to a stored procedure for server-side processing.
_, err = db.ExecContext(ctx,
"EXECUTE dbo.ProcessDepartmentMetadata @payload",
sql.Named("payload", string(jsonBytes)))
return err
}
Kullanım:
metadata := map[string]any{
"source": "docs-sample",
"batchId": "b-20260709-01",
"departments": []map[string]any{
{"name": "Data Science", "groupName": "Research and Development"},
{"name": "Cloud Ops", "groupName": "Information Technology"},
},
}
if err := sendJSONPayload(ctx, db, metadata); err != nil {
log.Fatal(err)
}
JSON'dan OPENJSON ile toplu ekleme
Bir JSON dizisinden birden fazla satır tek bir ifadeye ekleyin:
func bulkInsertFromJSON(ctx context.Context, db *sql.DB, jsonData string) (int64, error) {
result, err := db.ExecContext(ctx, `
INSERT INTO HumanResources.Department (Name, GroupName)
SELECT Name, GroupName
FROM OPENJSON(@json)
WITH (
Name NVARCHAR(50) '$.name',
GroupName NVARCHAR(50) '$.groupName'
)`, sql.Named("json", jsonData))
if err != nil {
return 0, err
}
return result.RowsAffected()
}
Kullanım:
jsonData := `[
{"name": "Data Science", "groupName": "Research and Development"},
{"name": "Cloud Ops", "groupName": "Information Technology"},
{"name": "Developer Relations", "groupName": "Sales and Marketing"}
]`
rowsInserted, err := bulkInsertFromJSON(ctx, db, jsonData)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Inserted %d rows\n", rowsInserted)
JSON_VALUE ve JSON_QUERY
Tüm JSON belgesini aktarmadan JSON sütunlarından değerleri çıkarın:
// Extract a scalar value.
var productName string
err := db.QueryRowContext(ctx, `
SELECT Name
FROM Production.Product
WHERE ProductID = @id`,
sql.Named("id", 1)).Scan(&productName)
if err != nil {
log.Fatal(err)
}
fmt.Println(productName)
// Extract a JSON array from a FOR JSON subquery.
var itemsJSON string
err = db.QueryRowContext(ctx, `
SELECT (
SELECT ProductID, Name
FROM Production.Product
WHERE ProductSubcategoryID = @subId
FOR JSON PATH
) AS Items`,
sql.Named("subId", 1)).Scan(&itemsJSON)
if err != nil {
log.Fatal(err)
}
fmt.Println(itemsJSON)
İpucu
JSON_VALUE Skaler bir değer (dizi, sayı) döndürür.
JSON_QUERY bir nesne veya diziyi döndürür. İhtiyacınız olan veri türü için doğru fonksiyonu kullanın.
JSON hesaplanan sütunlar ve indeksler
Sıkça sorgulanan JSON özellikleri için, daha iyi performans için hesaplanmış sütunlar ve indeksler oluşturun:
-- Demo table with JSON-only rows.
IF OBJECT_ID('dbo.ProductJsonDemo', 'U') IS NOT NULL
DROP TABLE dbo.ProductJsonDemo;
CREATE TABLE dbo.ProductJsonDemo (
ProductDescriptionID INT IDENTITY(1,1) PRIMARY KEY,
Metadata NVARCHAR(MAX) NOT NULL,
CONSTRAINT CK_ProductJsonDemo_Metadata_IsJson CHECK (ISJSON(Metadata) = 1),
-- Cast to a bounded length so the index key stays under SQL Server limits.
LocaleName AS CAST(JSON_VALUE(Metadata, '$.locale') AS NVARCHAR(10)) PERSISTED
);
INSERT INTO dbo.ProductJsonDemo (Metadata)
VALUES
(N'{"locale":"en","title":"Road helmet"}'),
(N'{"locale":"fr","title":"Casque de route"}');
CREATE INDEX IX_ProductJsonDemo_LocaleName ON dbo.ProductJsonDemo(LocaleName);
Sonra hesaplanan sütunu doğrudan Go'dan sorgulayın:
rows, err := db.QueryContext(ctx,
"SELECT ProductDescriptionID, LocaleName FROM dbo.ProductJsonDemo WHERE LocaleName = @name",
sql.Named("name", "en"))
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var localeName string
if err := rows.Scan(&id, &localeName); err != nil {
log.Fatal(err)
}
fmt.Printf("%d %s\n", id, localeName)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
XML verileri
Sorgu sonuçlarını FOR XML ile XML olarak alma
Sorgu sonuçlarını XML olarak döndürmek için kullanılır FOR XML PATH :
var xmlResult string
err := db.QueryRowContext(ctx, `
SELECT BusinessEntityID AS [@id], FirstName + ' ' + LastName AS Name, CountryRegionName AS Department
FROM Sales.vSalesPerson
WHERE CountryRegionName = @dept
FOR XML PATH('Employee'), ROOT('Employees')`,
sql.Named("dept", "United States")).Scan(&xmlResult)
if err != nil {
log.Fatal(err)
}
fmt.Println(xmlResult)
Sonuç:
<Employees>
<Employee id="274"><Name>Stephen Jiang</Name><Department>United States</Department></Employee>
<Employee id="275"><Name>Michael Blythe</Name><Department>United States</Department></Employee>
<Employee id="276"><Name>Linda Mitchell</Name><Department>United States</Department></Employee>
<Employee id="277"><Name>Jillian Carson</Name><Department>United States</Department></Employee>
<Employee id="279"><Name>Tsvi Reiter</Name><Department>United States</Department></Employee>
<Employee id="280"><Name>Pamela Ansman-Wolfe</Name><Department>United States</Department></Employee>
<Employee id="281"><Name>Shu Ito</Name><Department>United States</Department></Employee>
<Employee id="283"><Name>David Campbell</Name><Department>United States</Department></Employee>
<Employee id="284"><Name>Tete Mensa-Annan</Name><Department>United States</Department></Employee>
<Employee id="285"><Name>Syed Abbas</Name><Department>United States</Department></Employee>
<Employee id="287"><Name>Amy Alberts</Name><Department>United States</Department></Employee>
</Employees>
Büyük XML sonuçlarını yönetin
JSON gibi, büyük XML sonuçları da satırlara bölünür.
func queryXML(ctx context.Context, db *sql.DB, query string, args ...any) (string, error) {
rows, err := db.QueryContext(ctx, query, args...)
if err != nil {
return "", err
}
defer rows.Close()
var sb strings.Builder
for rows.Next() {
var chunk string
if err := rows.Scan(&chunk); err != nil {
return "", err
}
sb.WriteString(chunk)
}
if err := rows.Err(); err != nil {
return "", err
}
return sb.String(), nil
}
Go'da XML Sonuçlarını Ayrıştırma
XML sonuçlarını ayrıştırmak için encoding/xml paketini kullanın.
import "encoding/xml"
type EmployeeList struct {
XMLName xml.Name `xml:"Employees"`
Employees []Employee `xml:"Employee"`
}
type Employee struct {
ID int `xml:"id,attr"`
Name string `xml:"Name"`
Department string `xml:"Department"`
}
func getEmployeesXML(ctx context.Context, db *sql.DB, dept string) (*EmployeeList, error) {
xmlStr, err := queryXML(ctx, db, `
SELECT BusinessEntityID AS [@id], FirstName + ' ' + LastName AS Name, CountryRegionName AS Department
FROM Sales.vSalesPerson
WHERE CountryRegionName = @dept
FOR XML PATH('Employee'), ROOT('Employees')`,
sql.Named("dept", dept))
if err != nil {
return nil, err
}
var result EmployeeList
if err := xml.Unmarshal([]byte(xmlStr), &result); err != nil {
return nil, err
}
return &result, nil
}
XML parametrelerini SQL Server'a geçirin
Bir XML belgesini saklanan bir prosedüre veya sorguya gönderin:
xmlData := `<Employees>
<Employee><Name>Alice</Name><Department>Engineering</Department></Employee>
<Employee><Name>Bob</Name><Department>Marketing</Department></Employee>
</Employees>`
rows, err := db.QueryContext(ctx, `
DECLARE @xmlDoc XML = CAST(@xml AS XML);
SELECT
e.value('(Name)[1]', 'NVARCHAR(100)') AS Name,
e.value('(Department)[1]', 'NVARCHAR(100)') AS Department
FROM @xmlDoc.nodes('/Employees/Employee') AS t(e)`,
sql.Named("xml", xmlData))
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var name, dept string
if err := rows.Scan(&name, &dept); err != nil {
log.Fatal(err)
}
fmt.Printf("%s - %s\n", name, dept)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
Note
Parametre @xml varsayılan olarak nvarchar(max) olarak gönderilir.
.nodes() yöntemi, xml veri türünü gerektirir; bu nedenle parametreyi CAST(@xml AS XML) ile açıkça dönüştürün.
XML'den satır ekle
.nodes() XML'i tablo satırlarına parçalamak için bir INSERT...SELECT ifade ile yöntemi kullanın.
func bulkInsertFromXML(ctx context.Context, db *sql.DB, xmlData string) (int64, error) {
result, err := db.ExecContext(ctx, `
DECLARE @xmlDoc XML = CAST(@xml AS XML);
INSERT INTO HumanResources.Department (Name, GroupName)
SELECT
e.value('(Name)[1]', 'NVARCHAR(50)'),
e.value('(GroupName)[1]', 'NVARCHAR(50)')
FROM @xmlDoc.nodes('/Departments/Department') AS t(e)`,
sql.Named("xml", xmlData))
if err != nil {
return 0, err
}
return result.RowsAffected()
}
JSON ile XML arasında seçim yapın
| Consideration | JSON | XML |
|---|---|---|
| Go ekosistem desteği | Standart encoding/json. Haritalama için struktur etiketleri. |
Standart encoding/xml. Daha ayrıntılı yapı etiketleri. |
| SQL Server desteği |
OPENJSON, JSON_VALUE, JSON_QUERY, FOR JSON (SQL Server 2016 ve sonraki sürümler) |
nodes(), value(), query(), FOR XML (tüm versiyonlar) |
| Performance | Genel olarak daha hızlı ayrıştırma. Daha az ayrıntılı serileştirme biçimi. | Şemaları ve doğrulamayı destekler. Daha ayrıntılı. |
| Şema doğrulaması | SQL Server'da yerleşik şema doğrulaması yok. | Sunucu tarafı doğrulama için XML Şema Koleksiyonlarını destekler. |
| Dizin Oluşturma | JSON_VALUE + indeksli hesaplanmış sütunlar. | XML indeksleri (birincil ve ikincil). |
| Veri modelleme | Diziler ve iç içe nesneler. Go dilimleri ve haritalar için doğal uyum. | Nitelikleri ve isim alanları olan hiyerarşik belgeler. |
İpucu
Yeni geliştirme için genellikle JSON daha iyi bir seçimdir. Daha az ayrıştırma yükü gerektirir, daha küçük yükler üretir ve doğal olarak Go yapılarına eşlenir. Şema doğrulaması gerektiğinde veya XML gerektiren sistemlerle entegrasyon yaparken XML kullanın.