Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Este guia ajuda os programadores do Go a migrar do PostgreSQL, MySQL e outros drivers de base de dados para go-mssqldb o SQL Server. Cobre diferenças de sintaxe SQL, alterações específicas do driver e padrões equivalentes para operações comuns.
Note
Os exemplos deste artigo são executados na base de dados de exemplo AdventureWorks2025.
Porque migrar para o SQL Server com go-mssqldb
| Feature | SQL Server com go-mssqldb |
|---|---|
| Segurança empresarial | Sempre encriptado, segurança ao nível de linha, mascaramento dinâmico de dados, encriptação transparente de dados (TDE). |
| Authentication | Microsoft Entra ID (anteriormente Azure AD), identidade gerida, Windows authentication, Kerberos. |
| Integração com Azure | Suporte nativo para Base de Dados SQL do Azure com encriptação automática, ligações sem palavra-passe e gestão de failover. |
| Performance | Índices columnstore, OLTP na memória, arquivo de consultas para correção automática do plano. |
| Formatos de dados | Suporte integrado a JSON e XML com indexação e consulta do lado do servidor. |
| Tooling | Extensões SQL SQL Server Management Studio (SSMS), Azure Data Studio, Visual Studio Code SQL. |
Lista de verificação para considerações de migração
Reveja estes itens antes de começar a migrar as consultas linha a linha:
| Consideração | O que mudar |
|---|---|
| A sintaxe dos marcadores de posição difere da de muitos controladores Go. | Substitua ?, $1 e marcadores de posição semelhantes por @name ou @p1, em seguida passe os argumentos sql.Named() quando apropriado. |
LastInsertId() não é suportado. |
Use OUTPUT INSERTED.<column> ou SELECT SCOPE_IDENTITY() em vez disso. |
Os valores Go string são mapeados, por defeito, para tipos Unicode. |
Pressuponha a semântica de nvarchar, a menos que escolha um tipo específico do controlador, como mssql.VarChar, para dados que não sejam Unicode. |
| As tabelas temporárias estão limitadas à ligação física. | Mantenha a lógica de criar e usar uma tabela temporária na mesma ligação ou dentro da mesma transação, se as instruções posteriores dependerem dessa tabela. |
| A autenticação do Microsoft Entra utiliza um registo do controlador diferente. | Importa github.com/microsoft/go-mssqldb/azuread, usa sql.Open("azuresql", ...), e define explicitamente as opções TLS do SQL do Azure com encrypt=true&TrustServerCertificate=false. |
Para orientações mais aprofundadas nestas áreas, consulte Consultas e declarações, Limitações, Mapeamentos de tipos de dados, autenticação do Microsoft Entra ID e Resolução de problemas.
Migrar a partir de lib/pq (PostgreSQL)
Alterar o nome da importação e do piloto
Substitua a importação lib/pq e o nome do driver por go-mssqldb:
import _ "github.com/lib/pq"
db, err := sql.Open("postgres", connString)
// After (SQL Server with go-mssqldb):
import _ "github.com/microsoft/go-mssqldb"
db, err := sql.Open("sqlserver", connString)
Alterar o formato da cadeia de ligação
Converter o formato chave-valor do PostgreSQL para uma URL do SQL Server:
// lib/pq connection string:
"host=<server> port=5432 user=<user> password=<password> dbname=AdventureWorks2025 sslmode=require"
// go-mssqldb connection string:
"sqlserver://<user>:<password>@<server>:1433?database=AdventureWorks2025&encrypt=true"
Altere os marcadores de posição de parâmetros
O PostgreSQL usa $1, $2 marcadores posicionais. O SQL Server utiliza parâmetros nomeados com @:
// PostgreSQL (lib/pq):
db.QueryContext(ctx, "SELECT * FROM users WHERE id = $1 AND status = $2", id, status)
// SQL Server (go-mssqldb):
db.QueryContext(ctx, "SELECT ProductID, Name FROM Production.Product WHERE ProductID = @id AND Color = @color",
sql.Named("id", id),
sql.Named("color", color))
Alterações na sintaxe SQL
| Operation | PostgreSQL | SQL Server |
|---|---|---|
| Incremento automático |
SERIAL ou GENERATED ALWAYS AS IDENTITY |
IDENTITY(1,1) |
| Insira o ID | RETURNING id |
OUTPUT INSERTED.id ou SELECT SCOPE_IDENTITY() |
| Tipo booleano | BOOLEAN |
BIT |
| Concatenação de cordas | \|\| |
+ ou CONCAT() |
| Carimbo de data/hora atual |
NOW() ou CURRENT_TIMESTAMP |
GETUTCDATE() ou SYSDATETIMEOFFSET() |
| Limitar linhas | LIMIT 10 OFFSET 20 |
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY |
| Tipo de string |
TEXT ou VARCHAR |
NVARCHAR(MAX) ou NVARCHAR(n) |
| Extração JSON | column->>'key' |
JSON_VALUE(column, '$.key') |
| Upsert | INSERT ... ON CONFLICT DO UPDATE |
Declaração MERGE |
| Tipo de matriz | INTEGER[] |
Sem matrizes nativas. Usa parâmetros com valores de tabela. |
| Sensível às maiúsculas e minúsculas | Sensível a maiúsculas minúsculas por defeito | Não distingue entre maiúsculas e minúsculas por predefinição (depende da ordenação). |
Obter o ID introduzido
Substitua a cláusula do RETURNING PostgreSQL pela cláusula do OUTPUT SQL Server:
var id int
err := db.QueryRowContext(ctx,
"INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id",
name, email).Scan(&id)
// SQL Server (go-mssqldb) using OUTPUT:
var id int
err := db.QueryRowContext(ctx,
"INSERT INTO HumanResources.Department (Name, GroupName) OUTPUT INSERTED.DepartmentID VALUES (@name, @groupName)",
sql.Named("name", name),
sql.Named("groupName", groupName)).Scan(&id)
Pagination
Substitua a sintaxe LIMIT/OFFSET pela sintaxe OFFSET/FETCH NEXT.
// PostgreSQL:
"SELECT * FROM employees ORDER BY id LIMIT $1 OFFSET $2"
// SQL Server (requires ORDER BY):
"SELECT ProductID, Name, ListPrice FROM Production.Product ORDER BY ProductID OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY"
Migrar a partir de pgx (PostgreSQL)
O pgx driver utiliza o seu próprio pool de ligações e API, que diferem de database/sql. Para migrar, mude para a interface padrão database/sql .
Mudança de pool pgx para base de dados/sql
Substitua a pgxpool API pela interface padrão database/sql .
// Before (pgx):
import "github.com/jackc/pgx/v5/pgxpool"
pool, err := pgxpool.New(ctx, "postgres://user:pass@<server>:5432/AdventureWorks2025")
defer pool.Close()
rows, err := pool.Query(ctx, "SELECT * FROM users WHERE id = $1", id)
// After (go-mssqldb with database/sql):
import (
"database/sql"
_ "github.com/microsoft/go-mssqldb"
)
db, err := sql.Open("sqlserver", "sqlserver://user:pass@<server>:1433?database=AdventureWorks2025")
defer db.Close()
rows, err := db.QueryContext(ctx,
"SELECT ProductID, Name FROM Production.Product WHERE ProductID = @id", sql.Named("id", id))
Substituir funcionalidades específicas do pgx
| funcionalidade pgx | Equivalente a go-mssqldb |
|---|---|
pgx.CollectRows |
Manual rows.Next() e rows.Scan() ciclo. |
pgx.RowToStructByName |
Manualmente rows.Scan nos campos da estrutura. |
Consultas em lote (pgx.Batch) |
Várias chamadas ExecContext ou procedimentos armazenados. |
COPY FROM para inserção a granel |
mssql.CopyIn Para inserção a granel. |
pgx.ConnConfig |
msdsn.Config ou cadeias de ligação baseadas em URL. |
pgxpool.Pool |
sql.DB com SetMaxOpenConns e SetMaxIdleConns. |
Migrar de go-sql-driver/mysql (MySQL)
Troque a importação do MySQL e o nome do driver
Substitua a instrução de importação do MySQL e o nome do driver por go-mssqldb.
// Before (MySQL):
import _ "github.com/go-sql-driver/mysql"
db, err := sql.Open("mysql", connString)
// After (SQL Server):
import _ "github.com/microsoft/go-mssqldb"
db, err := sql.Open("sqlserver", connString)
Converter o formato DSN do MySQL
Converta o formato MySQL DSN para uma URL do SQL Server.
// MySQL DSN:
"user:password@tcp(<server>:3306)/AdventureWorks2025?tls=true"
// go-mssqldb URL:
"sqlserver://user:password@<server>:1433?database=AdventureWorks2025&encrypt=true"
Substituir os marcadores de posição com ponto de interrogação
O MySQL utiliza ? marcadores posicionais.
// MySQL:
db.QueryContext(ctx, "SELECT * FROM users WHERE id = ? AND status = ?", id, status)
// SQL Server:
db.QueryContext(ctx, "SELECT ProductID, Name FROM Production.Product WHERE ProductID = @id AND Color = @color",
sql.Named("id", id),
sql.Named("color", color))
Compare a sintaxe do MySQL e do SQL Server
| Operation | MySQL | SQL Server |
|---|---|---|
| Incremento automático | AUTO_INCREMENT |
IDENTITY(1,1) |
| Insira o ID | LAST_INSERT_ID() |
SCOPE_IDENTITY() ou OUTPUT INSERTED.id |
| Limitar linhas | LIMIT 10 OFFSET 20 |
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY |
| Carimbo de data/hora atual | NOW() |
GETUTCDATE() |
| Se nulo | IFNULL(expr, default) |
ISNULL(expr, default) ou COALESCE(expr, default) |
| Comprimento da cadeia | LENGTH(str) |
LEN(str) |
| Substring | SUBSTRING(str, start, len) |
SUBSTRING(str, start, len) (mesmo) |
| Formato de data | DATE_FORMAT(d, '%Y-%m-%d') |
FORMAT(d, 'yyyy-MM-dd') ou CONVERT(VARCHAR, d, 23) |
| Upsert | INSERT ... ON DUPLICATE KEY UPDATE |
Declaração MERGE |
| Citação de backticks | `column` |
[column] |
Substituir a sintaxe específica do MySQL
| Sintaxe MySQL | Equivalente ao SQL Server |
|---|---|
AUTO_INCREMENT |
IDENTITY(1,1) |
LIMIT n OFFSET m |
OFFSET m ROWS FETCH NEXT n ROWS ONLY (necessita de ORDER BY) |
AUTO_INCREMENT para IDENTITY:
-- MySQL:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100)
);
-- SQL Server:
CREATE TABLE HumanResources.NewDepartment (
DepartmentID SMALLINT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(50) NOT NULL
);
LIMIT para OFFSET/FETCH:
-- MySQL:
SELECT * FROM users LIMIT 10 OFFSET 20;
-- SQL Server:
SELECT ProductID, Name, ListPrice
FROM Production.Product
ORDER BY ProductID
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
Padrões migratórios comuns
Obter o último identificador inserido
Utilize a cláusula OUTPUT ou SCOPE_IDENTITY() para recuperar o valor de identidade da linha inserida:
// Pattern 1: OUTPUT clause (recommended, works with batch inserts).
var id int64
err := db.QueryRowContext(ctx,
"INSERT INTO HumanResources.Department (Name, GroupName) OUTPUT INSERTED.DepartmentID VALUES (@name, @groupName)",
sql.Named("name", "Engineering"),
sql.Named("groupName", "Research and Development")).Scan(&id)
// Pattern 2: SCOPE_IDENTITY (works with single-row inserts).
var id int64
err := db.QueryRowContext(ctx,
"INSERT INTO HumanResources.Department (Name, GroupName) VALUES (@name, @groupName); SELECT SCOPE_IDENTITY()",
sql.Named("name", "Engineering"),
sql.Named("groupName", "Research and Development")).Scan(&id)
Tip
Prefira a OUTPUT cláusula em vez de SCOPE_IDENTITY(). A cláusula OUTPUT funciona com inserções por lotes e não depende da ordenação das instruções.
Upsert (inserir ou atualizar)
O ON CONFLICT PostgreSQL e o ON DUPLICATE KEY UPDATE MySQL correspondem ao MERGE SQL Server:
_, err := db.ExecContext(ctx, `
MERGE HumanResources.Department AS target
USING (SELECT @id AS DepartmentID, @name AS Name, @groupName AS GroupName) AS source
ON target.DepartmentID = source.DepartmentID
WHEN MATCHED THEN
UPDATE SET Name = source.Name, GroupName = source.GroupName, ModifiedDate = GETDATE()
WHEN NOT MATCHED THEN
INSERT (Name, GroupName, ModifiedDate) VALUES (source.Name, source.GroupName, GETDATE());`,
sql.Named("id", dept.ID),
sql.Named("name", dept.Name),
sql.Named("groupName", dept.GroupName))
Inserção em massa
Substitua PostgreSQL COPY ou MySQL LOAD DATA por mssql.CopyIn.
import mssql "github.com/microsoft/go-mssqldb"
stmt, err := db.Prepare(mssql.CopyIn("HumanResources.Department", mssql.BulkOptions{}, "Name", "GroupName", "ModifiedDate"))
if err != nil {
return err
}
for _, dept := range departments {
_, err = stmt.Exec(dept.Name, dept.GroupName, time.Now())
if err != nil {
return err
}
}
// Flush the buffer.
_, err = stmt.Exec()
if err != nil {
return err
}
stmt.Close()
Controlar valores NULL
Todos os drivers de base de dados do Go tratam os valores NULL da mesma forma porque usam os tipos database/sql .
var color sql.NullString
err := db.QueryRowContext(ctx,
"SELECT Color FROM Production.Product WHERE ProductID = @id",
sql.Named("id", 1)).Scan(&color)
if color.Valid {
fmt.Println(color.String)
} else {
fmt.Println("NULL")
}
Transactions
Todos os drivers da base de dados Go usam a mesma database/sql API de transações.
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return err
}
defer tx.Rollback()
_, err = tx.ExecContext(ctx,
"UPDATE Production.ProductInventory SET Quantity = Quantity - @qty WHERE ProductID = @pid AND LocationID = @fromLoc",
sql.Named("qty", qty),
sql.Named("pid", productID),
sql.Named("fromLoc", fromLocationID))
if err != nil {
return err
}
_, err = tx.ExecContext(ctx,
"UPDATE Production.ProductInventory SET Quantity = Quantity + @qty WHERE ProductID = @pid AND LocationID = @toLoc",
sql.Named("qty", qty),
sql.Named("pid", productID),
sql.Named("toLoc", toLocationID))
if err != nil {
return err
}
return tx.Commit()
Lista de verificação da migração
| Step | Action |
|---|---|
| Instale o controlador | go get github.com/microsoft/go-mssqldb |
| Alterar importações | Substitua a importação do antigo driver por _ "github.com/microsoft/go-mssqldb". |
| Atualizar cadeias de ligação | Alteração para o formato URL do SQL Server: sqlserver://user:pass@host?database=db. |
| Substituir marcadores de parâmetros | Altere $1/$2 ou ? para @name com sql.Named. |
| Atualizar sintaxe SQL | Alterar LIMIT/OFFSET, RETURNING, NOW(), SERIAL, e outros SQL específicos da base de dados. |
| Substituir operações a grande escala | Mudança COPY ou LOAD DATA para mssql.CopyIn. |
| Atualizar esquema DDL | Muda SERIAL/AUTO_INCREMENT para IDENTITY, TEXT para NVARCHAR, BOOLEAN para BIT. |
| Teste todas as consultas | Executa o teu conjunto de testes contra uma instância do SQL Server para detetar diferenças de sintaxe. |
| Configurar criptografia | Adicionar encrypt=true (ou confiar na deteção automática do Azure) para produção. |
| Configurar a autenticação | Configure o Microsoft Entra ID para Azure, ou a autenticação do SQL Server para instalações locais. |