Standard Operating Procedure

PostgreSQL → SQL Server / Azure SQL

Step-by-step procedure for migrating a PostgreSQL 13+ database to SQL Server 2019+ or Azure SQL Database using Endrias Bridge, including prerequisites, type-conversion guidance, and post-migration validation.

Tool: Endrias Bridge  ·  Source: PostgreSQL 13+  ·  Target: SQL Server 2019+ or Azure SQL Database

📖 Overview & Scope

This SOP covers a full copy (schema + data) from a PostgreSQL 13+ source into a SQL Server 2019+ or Azure SQL Database target using the Endrias Bridge GUI. All tables in the selected schema are migrated; PostgreSQL-specific types (BOOLEAN, SERIAL, UUID, JSONB, ARRAY, PostGIS) are converted automatically, with warnings logged for any lossy mappings.

ℹ️
Bidirectional support: Endrias Bridge also supports SQL Server → PostgreSQL — see SOP_AdventureWorks2019_to_PostgreSQL.html.

Prerequisites — Source (PostgreSQL)

Run the following checks and grants on the source PostgreSQL server before starting the migration wizard:

-- Check WAL level (must be 'logical' for CDC mode; restart required to change)
SHOW wal_level;

-- Check replication slot capacity (must be >= 2 for CDC mode)
SHOW max_replication_slots;

-- Recommended: set in postgresql.conf
-- wal_keep_size = 51200    (MB)

-- Grant migration user access
GRANT CONNECT ON DATABASE EndriasBridge TO MigrationUser;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO MigrationUser;

-- CDC mode only (requires REPLICATION role):
-- ALTER ROLE MigrationUser REPLICATION;
RequirementVerify
PostgreSQL 13+ accessible from migration hostVerify
wal_level = logical — required for CDC; full-copy does not need it (restart to change)SHOW wal_level;
max_replication_slots >= 2SHOW max_replication_slots;
wal_keep_size = 51200 (MB) in postgresql.conf, or active replication slotCheck conf
MigrationUser has CONNECT + SELECT on all tables in EndriasBridgeRun grants above
TCP port 5432 open from migration host to PostgreSQL serverNetwork check

Prerequisites — Target (SQL Server / Azure SQL)

RequirementVerify
SQL login MigrationUser with db_owner on target database EndriasBridgeTargetVerify
ODBC Driver 17 for SQL Server installed on migration hostVerify
TCP 1433 open from migration host to target SQL Server / Azure SQLNetwork check
Target database EndriasBridgeTarget pre-created, or use "Auto-create" checkbox in Migration Projects Step 3Create DB
Azure SQL only: Add migration host public IP to server firewall rules in Azure PortalIf Azure SQL
💡
For Azure SQL Database the host is sql-target.database.windows.net. Enable Allow Azure services and resources to access this server in the Azure Portal firewall settings if the migration host is also in Azure.
1

Configure Connections

Open Endrias Bridge and navigate to Migration Projects. Create a new project and fill in both connection blocks as shown:

  Endrias Bridge — New Migration Project
Migration Projects
Assessment
Jobs
Schema Objects
Tools
Source & Target Configuration
Configure source and target database connections.

SOURCE DATABASE

PostgreSQL
pg-source-server
5432
EndriasBridge
MigrationUser
••••••••••••

TARGET DATABASE

SQL Server
sql-target.database.windows.net
1433
EndriasBridgeTarget
MigrationUser
••••••••••••
Test Connections
Save Project
💡
Click Test Connections before proceeding. Both source and target must return a green checkmark. A failed target connection at this stage is usually a firewall rule or missing database — not a credentials issue.
2

Run Assessment

Switch to the Assessment tab and click Run Assessment. Endrias Bridge will enumerate all tables and columns on the PostgreSQL source and report type-compatibility warnings before any data is moved.

  Endrias Bridge
Migration Projects
Assessment
Jobs
Schema Objects
Tools
Database Assessment
Discovers source objects and checks compatibility with target engine.
Run Assessment

SOURCE OBJECTS

📁 Tables (44)
  public.users   19,700 rows
  public.orders   88,200 rows
  public.products   4,300 rows
  public.events   440,000 rows
  … (40 more)

COMPATIBILITY WARNINGS

• users.active: BOOLEAN → BIT
• users.id: SERIAL → INT IDENTITY(1,1)
• orders.uid: UUID → UNIQUEIDENTIFIER
• products.metadata: JSONB → NVARCHAR(MAX)
• events.tags: TEXT[] → NVARCHAR(MAX) [WARNING]
• … (full list per table)
ℹ️
Review all WARNING entries — these are lossy conversions (ARRAY types, PostGIS geometry). Application queries touching those columns will need updating post-migration. See the Type Conversions reference table for the full mapping.
3

Select Tables

Return to Migration Projects. Click Load Tables from Source. All 44 tables are selected by default. Deselect any tables you want to skip. Enable Auto-create target DB if EndriasBridgeTarget does not yet exist on the target server.

  Endrias Bridge
Migration Projects
Assessment
Jobs
Schema Objects
Tools
Migrate Schema & Data
Select tables and copy schema / data to target database.
Migrate schema (CREATE TABLE)
Migrate data (INSERT rows)
Auto-create target DB
Sync mode:
Full copy
Incremental (watermark column)
CDC (logical replication)
Load Tables from Source
Start Migration
Verify Data Integrity
Export Report
users
orders
products
events
… (40 more, all checked)
⚠️
Tables with PostGIS geometry/geography columns will migrate, but those columns become NVARCHAR(MAX) WKT text. If spatial queries are required on the SQL Server target, plan a post-migration conversion to SQL Server's native spatial types (geometry/geography).
4

Start Migration & Monitor

Click Start Migration. The migration log updates live as each table's schema is created and rows are bulk-copied. Review all WARNING lines before closing the panel.

  Endrias Bridge — Migration Log
14:02:11 --- Data type conversions (PostgreSQL -> SQL Server) ---
14:02:11 EndriasBridge.users.active: BOOLEAN -> BIT
14:02:11 EndriasBridge.users.id: SERIAL -> INT IDENTITY(1,1)
14:02:11 EndriasBridge.orders.uid: UUID -> UNIQUEIDENTIFIER
14:02:11 EndriasBridge.products.metadata: JSONB -> NVARCHAR(MAX) [stored as JSON text]
14:02:11 EndriasBridge.events.tags: TEXT[] -> NVARCHAR(MAX) [serialized array — WARNING]
14:02:12 Schema: created 44 table(s)
14:02:12 [1/44] users ... 19,700 row(s)
14:02:13 [2/44] orders ... 88,200 row(s)
14:02:45 --- Full copy: 980,000+ row(s) in 24s ---
14:02:45 --- Done ---
⚠️
Any line marked WARNING (e.g. ARRAY serialization) requires follow-up. Do not hand off the migration until --- Done --- appears and the total row count matches expectations from the source.
5

Verify & Export Report

  1. Click Verify Data Integrity — compares source vs. target row counts for every migrated table and logs any mismatches.
  2. Manually spot-check rows in tables flagged with WARNING (ARRAY, JSONB, geometry columns).
  3. Click Export Report (enabled once migration finishes) to save an HTML summary of all tables created, rows copied, type conversions applied, and warnings generated.
  4. Archive the report with the project change ticket for sign-off.
6

Post-Migration Tasks

Complete the following tasks on the target SQL Server / Azure SQL after verifying row counts:

-- 1. Reset IDENTITY seeds to the current max migrated value
DBCC CHECKIDENT ('EndriasBridgeTarget.dbo.users', RESEED);
-- Repeat for every table with an IDENTITY column.

-- 2. JSONB columns are stored as NVARCHAR(MAX) — update app queries
-- PostgreSQL:  WHERE metadata->>'key' = 'value'
-- SQL Server:  WHERE JSON_VALUE(metadata, '$.key') = 'value'
--              or use OPENJSON() for multi-row extraction

-- 3. Array columns serialized to NVARCHAR(MAX) — notify application team
-- Application must parse the serialized text format.

-- 4. Rebuild fragmented indexes after bulk insert
ALTER INDEX ALL ON dbo.users REBUILD;
-- Repeat for each migrated table.

-- 5. Update statistics
UPDATE STATISTICS dbo.users;
Post-Migration TaskPriority
Reset IDENTITY seeds: DBCC CHECKIDENT for all identity tablesRequired
Update JSONB app queries to use JSON_VALUE() / OPENJSON()Required
Notify application team of serialized ARRAY columns (NVARCHAR(MAX))Required
Update BOOLEAN literal comparisons (TRUE/FALSE → 1/0)Required
Rebuild indexes on all migrated tablesRecommended
Validate PostGIS geometry columns converted to WKT NVARCHAR(MAX) — convert if spatial queries neededIf applicable
Scale target DTUs/vCores back to steady-state after migration completesRecommended

⚠️ Known Issues

IssueDetailAction Required
ARRAY types All PostgreSQL array columns are serialized to NVARCHAR(MAX). A WARNING is logged for every affected column. SQL Server has no native array type. Update application array-parsing logic
JSONB / JSON Stored as NVARCHAR(MAX) (JSON text is preserved verbatim). Use JSON_VALUE() / OPENJSON() on SQL Server. Update application queries
BOOLEAN → BIT TRUE/FALSE become 1/0. Application string literals like 'true' must be updated. Update literal comparisons
SERIAL / BIGSERIAL Become INT IDENTITY(1,1) / BIGINT IDENTITY(1,1). Identity seeds may diverge after bulk insert. Run DBCC CHECKIDENT post-migration
UUID → UNIQUEIDENTIFIER Values preserved. PostgreSQL stores lowercase hex; SQL Server stores uppercase. No functional difference. None — cosmetic only
CIDR / INET Stored as NVARCHAR(45) (text representation of IP/subnet). Update IP-range queries if any
PostGIS geometry / geography Stored as NVARCHAR(MAX) WKT via .ToString(). Lossy — spatial operations not available without post-migration conversion. Convert WKT to SQL Server spatial types if needed
Case sensitivity All identifiers lowercased. PostgreSQL public schema maps to dbo; other schemas are preserved. Review schema-qualified queries
Standalone sequences Standalone PostgreSQL sequences (not tied to SERIAL) are not migrated. Only IDENTITY columns are created. Recreate sequences manually if needed

📊 Type Conversions Applied (PostgreSQL → SQL Server)

Source (PostgreSQL)Target (SQL Server)Note
BOOLEANBITTRUE/FALSE → 1/0
SMALLINTSMALLINT
INTEGERINT
BIGINTBIGINT
SERIALINT IDENTITY(1,1)Run DBCC CHECKIDENT post-migration
BIGSERIALBIGINT IDENTITY(1,1)
REALREAL
DOUBLE PRECISIONFLOAT
NUMERIC(p,s)DECIMAL(p,s)
CHAR(n)NCHAR(n)
VARCHAR(n)NVARCHAR(n)
TEXTNVARCHAR(MAX)
BYTEAVARBINARY(MAX)
DATEDATE
TIMETIME
TIMESTAMPDATETIME2
TIMESTAMPTZDATETIMEOFFSETUTC offset preserved
UUIDUNIQUEIDENTIFIER
JSON / JSONBNVARCHAR(MAX)Use JSON_VALUE / OPENJSON on SQL Server
ARRAY (any)NVARCHAR(MAX)Serialized — WARNING logged
CIDR / INETNVARCHAR(45)Text representation
geometry / geographyNVARCHAR(MAX)WKT via .ToString() — lossy
OID / XMLNVARCHAR(MAX)