다른 드라이버에서 go-mssqldb로 마이그레이션하세요

이 가이드는 Go 개발자들이 PostgreSQL, MySQL 및 기타 데이터베이스 드라이버에서 SQL Server용으로 마이그레이션하는 go-mssqldb 데 도움을 줍니다. SQL 문법 차이, 드라이버별 변경 사항, 그리고 일반적인 연산에 적용되는 동등한 패턴을 다룹니다.

메모

이 글의 예시들은 AdventureWorks2025 샘플 데이터베이스를 기준으로 합니다.

왜 go-mssqldb와 함께 SQL Server로 마이그레이션해야 하나요?

특징 go-mssqldb용 SQL Server
엔터프라이즈 보안 항상 암호화, 행 수준 보안, 동적 데이터 마스킹, 투명 데이터 암호화(TDE).
Authentication Microsoft Entra ID (구 Azure AD), 관리 식별, Windows 인증, Kerberos.
Azure 통합 자동 암호화, 비밀번호 없는 연결, 페일오버 처리가 포함된 네이티브 Azure SQL Database 지원.
Performance 컬럼스토어 인덱스, 인메모리 OLTP, 자동 계획 수정을 위한 쿼리 스토어.
데이터 형식 서버 측 인덱싱 및 쿼리가 포함된 내장 JSON 및 XML 지원.
Tooling SQL Server Management Studio (SSMS), Azure Data Studio, Visual Studio Code SQL 확장 프로그램.

이주 고려사항 체크리스트

쿼리를 한 줄 포팅하기 전에 다음 항목들을 검토하세요:

고려 사항 변경할 내용
자리 표시자 구문은 많은 Go 드라이버와 다릅니다. ?, $1 및 이와 유사한 자리 표시자를 @name 또는 @p1로 바꾼 다음, 적절한 경우 sql.Named() 인수를 전달합니다.
LastInsertId()는 지원되지 않습니다. 대신 OUTPUT INSERTED.<column> 또는 SELECT SCOPE_IDENTITY()를 사용하십시오.
Go string 값은 기본적으로 유니코드 타입에 매핑됩니다. 비유니코드 데이터의 경우 mssql.VarChar와 같은 드라이버별 형식을 선택하지 않는 한 nvarchar 의미 체계를 예상하세요.
임시 테이블은 물리적 연결 범위로 제한됩니다. 이후 구문이 해당 테이블에 의존하는 경우, 임시 테이블을 생성하고 사용하는 로직은 동일한 연결에서 유지하거나 동일한 트랜잭션 내에 두세요.
Microsoft Entra 인증은 다른 드라이버 등록을 사용합니다. github.com/microsoft/go-mssqldb/azuread을(를) 가져오고, sql.Open("azuresql", ...)을(를) 사용하고, encrypt=true&TrustServerCertificate=false를 사용해 Azure SQL TLS 옵션을 명시적으로 설정하세요.

이 영역에 대한 더 깊은 안내는 쿼리 및 문, 제한,데이터 타입 매핑, Microsoft Entra ID 인증, 문제 해결을 참조하세요.

lib/pq (PostgreSQL)에서 마이그레이션하기

가져오기 이름과 드라이버 이름을 변경하세요

lib/pq import 및 드라이버 이름을 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)

연결 문자열 형식을 변경하세요

PostgreSQL 키값 형식을 SQL Server URL로 변환하세요:

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

매개변수 자리 표시자 변경

PostgreSQL은 $1, $2 위치 지정 자리 표시자를 사용합니다. SQL Server는 다음과 같은 @이름 있는 매개변수를 사용합니다:

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

SQL 문법 변경

Operation PostgreSQL SQL Server
자동 증가 SERIAL 또는 GENERATED ALWAYS AS IDENTITY IDENTITY(1,1)
삽입된 ID 가져오기 RETURNING id OUTPUT INSERTED.id 또는 SELECT SCOPE_IDENTITY()
불리언 자료형 BOOLEAN BIT
문자열 연결 \|\| + 또는 CONCAT()
현재 타임스탬프 NOW() 또는 CURRENT_TIMESTAMP GETUTCDATE() 또는 SYSDATETIMEOFFSET()
행 제한 LIMIT 10 OFFSET 20 OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
문자열 유형 TEXT 또는 VARCHAR NVARCHAR(MAX) 또는 NVARCHAR(n)
JSON 추출 column->>'key' JSON_VALUE(column, '$.key')
업서트 INSERT ... ON CONFLICT DO UPDATE MERGE 진술
배열 형식 INTEGER[] 네이티브 어레이는 없습니다. 테이블 값 매개변수를 사용하세요.
대/소문자 구분 기본적으로 대소문자를 구분함 기본적으로 대소문자 구분이 안 됩니다(콜레이션에 따라 다릅니다).

삽입된 신분증을 받아보세요

PostgreSQL의 절을 RETURNING SQL Server의 OUTPUT 절로 대체하세요:

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)

페이지 나누기

LIMIT / OFFSET 구문을 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"

pgx(PostgreSQL)에서 마이그레이션하기

pgx 드라이버는 database/sql와는 다른 자체 연결 풀과 API를 사용합니다. 마이그레이션하려면 표준 database/sql 인터페이스로 전환하세요.

pgx 풀에서 데이터베이스/SQL로의 변경

API를 pgxpool 표준 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))

PGX 전용 기능 교체

PGX 기능 Go-MSSQLDB 동등
pgx.CollectRows 수동 rows.Next()rows.Scan() 루프.
pgx.RowToStructByName 매뉴얼로 Struct rows.Scan 필드를 조작하세요.
배치 쿼리 (pgx.Batch) 여러 ExecContext 호출이나 저장 프로시저.
COPY FROM 대량 인서트용 mssql.CopyIn 대량 인서트용입니다.
pgx.ConnConfig msdsn.Config 또는 URL 기반 연결 문자열을 사용했습니다.
pgxpool.Pool SetMaxOpenConnsSetMaxIdleConns가 있는 sql.DB.

go-sql-driver/mysql (MySQL)에서 마이그레이션하세요

MySQL 가져오기와 드라이버 이름을 바꾸세요

MySQL 가져오기와 드라이버 이름을 .로 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)

MySQL DSN 형식을 변환하세요

MySQL DSN 형식을 SQL Server URL로 변환하세요.

// MySQL DSN:
"user:password@tcp(<server>:3306)/AdventureWorks2025?tls=true"

// go-mssqldb URL:
"sqlserver://user:password@<server>:1433?database=AdventureWorks2025&encrypt=true"

물음표 자리 표시자 교체

MySQL은 위치 플레이스홀더를 사용합니다 ? .

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

MySQL과 SQL Server 문법 비교

Operation MySQL SQL Server
자동 증가 AUTO_INCREMENT IDENTITY(1,1)
삽입된 ID 가져오기 LAST_INSERT_ID() SCOPE_IDENTITY() 또는 OUTPUT INSERTED.id
행 제한 LIMIT 10 OFFSET 20 OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
현재 타임스탬프 NOW() GETUTCDATE()
null이라면 IFNULL(expr, default) ISNULL(expr, default) 또는 COALESCE(expr, default)
문자열 길이 LENGTH(str) LEN(str)
Substring SUBSTRING(str, start, len) SUBSTRING(str, start, len) (동일)
날짜 형식 DATE_FORMAT(d, '%Y-%m-%d') FORMAT(d, 'yyyy-MM-dd') 또는 CONVERT(VARCHAR, d, 23)
업서트 INSERT ... ON DUPLICATE KEY UPDATE MERGE 진술
백틱 인용 `column` [column]

MySQL 고유 문법 교체

MySQL 문법 SQL Server 동등
AUTO_INCREMENT IDENTITY(1,1)
LIMIT n OFFSET m OFFSET m ROWS FETCH NEXT n ROWS ONLY(필요)ORDER BY

AUTO_INCREMENT에서 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
);

OFFSET/FETCH에 대한 LIMIT:

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

일반적인 마이그레이션 패턴

마지막으로 삽입된 ID 값 가져오기

삽입된 행의 IDENTITY 값을 검색하려면 OUTPUT 절 또는 SCOPE_IDENTITY()를 사용하세요:

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

SCOPE_IDENTITY()보다 OUTPUT 조항을 선호하세요. 이 절은 OUTPUT 배치 삽입 항목에 적용되며 명세서 순서에 의존하지 않습니다.

업서트 (삽입 또는 업데이트)

PostgreSQL의 ON CONFLICT 및 MySQL의 ON DUPLICATE KEY UPDATE은 SQL Server의 MERGE에 매핑됩니다:

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

대량 삽입

PostgreSQL의 COPY 또는 MySQL의 LOAD DATAmssql.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()

NULL 값 처리

모든 Go 데이터베이스 드라이버는 타입을 database/sql 사용하기 때문에 NULL 값을 동일하게 처리합니다.

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

모든 Go 데이터베이스 드라이버는 동일한 database/sql 트랜잭션 API를 사용합니다.

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

마이그레이션 검사 목록

Step 조치
드라이버 설치 go get github.com/microsoft/go-mssqldb
가져오기 변경 이전 드라이버 임포트를 .로 _ "github.com/microsoft/go-mssqldb"교체하세요.
연결 문자열 업데이트 SQL Server URL 형식으로의 변경: sqlserver://user:pass@host?database=db.
매개변수 자리 표시자 교체 sql.Named을 사용하여 $1/$2 또는 ?@name(으)로 변경하세요.
SQL 문법 업데이트 변경LIMIT/OFFSET, RETURNING, NOW(), SERIAL, 그리고 기타 데이터베이스별 SQL.
대량 작업 바꾸기 COPY 또는 LOAD DATAmssql.CopyIn로 변경하세요.
스키마 업데이트 DDL SERIAL, , /AUTO_INCREMENT, IDENTITY 로 변환.TEXTNVARCHARBOOLEANBIT
모든 쿼리를 테스트하세요 테스트 스위트를 SQL Server 인스턴스와 비교해 문법 차이를 찾아보세요.
암호화 구성 프로덕션 환경에서는 encrypt=true를 추가하거나 Azure 자동 감지를 사용하세요.
인증 설정 Azure용 Microsoft Entra ID 또는 온프레미스용 SQL Server 인증을 설정하세요.