Eine Datenmigration von SQL Server nach PostgreSQL scheitert selten am eigentlichen Kopieren der Daten. Sie scheitert an den stillen Unterschieden, die erst im Ziel auffallen: datetime, das keine Zeitzone kennt, bit, das kein boolean ist, ein IDENTITY, das zur Sequenz wird, und eine Collation, die plötzlich case-sensitiv vergleicht. Wer SQL Server nach PostgreSQL migrieren will, kopiert nicht einfach Tabellen — er übersetzt Typen, Schema, Code und Verhalten von einer Engine in eine andere.
Dieser Leitfaden ordnet den Umzug in fünf Phasen und benennt für jede die wichtigsten Stolperfallen. In die Tiefe geht jeweils ein eigener Artikel — dieser hier liefert den roten Faden, der die Phasen verbindet.
Das Wichtigste vorab:
- Fünf Phasen statt „Daten-Umzug“: Der Umzug zerfällt in Datentypen, Schema/DDL, Datentransfer, Code-Portierung und Verifikation. Wer sie in dieser Reihenfolge angeht, erspart sich die typischen Rückschläge.
- Jede Phase mit eigener Stolperfalle: Mal sind es kippende Typen, mal wird
IDENTITYzur Sequenz, mal die Transfer-Methode oder die Übersetzung von T-SQL nach PL/pgSQL. Keine davon fällt auf, bis sie im Ziel zuschlägt — deshalb steht am Ende die Verifikation. - Was Tooling abnimmt: Werkzeuge wie
pgloadererledigen die mechanischen rund 80 % — die unkritischen Typen und den Massentransfer. Die letzten 20 % — Typ-Edge-Cases, Prozedur-Logik, Trigger — bleiben Handarbeit. - Der rote Faden: Jede Phase hat ihren eigenen Detail-Artikel mit der vollen Tiefe. Dieser Hub verbindet sie und sagt, in welcher Reihenfolge sie zusammenspielen.
Voraussetzung: Grundverständnis relationaler Datenbanken. SQL Server 2017+ als Quelle, PostgreSQL 16/17 als Ziel. Postgres-Konzepte (Sequenzen, text, COPY, PL/pgSQL) werden bei der ersten Nennung kurz eingeordnet — Vorwissen über Postgres ist nicht nötig, T-SQL-Grundlagen schon.
Inhalt
- Warum SQL Server nach PostgreSQL migrieren?
- Der Migrationspfad in fünf Phasen
- Eine Tabelle, mehrere Phasen auf einmal
- Was Tooling abnimmt — und wo Handarbeit bleibt
- FAQ
- Verwandte Artikel
Warum SQL Server nach PostgreSQL migrieren?
Die Gründe sind selten technischer Natur — sie sind meist wirtschaftlich oder strategisch. Lizenzkosten fallen weg: PostgreSQL ist quelloffen und ohne Core- oder CAL-Lizenzen nutzbar. Der Open-Source-Stack lässt sich frei auf jeder Infrastruktur betreiben, ohne Bindung an einen Hersteller. Und die Cloud-Portabilität ist hoch — nahezu jeder Anbieter betreibt verwaltetes PostgreSQL.
Das ist kein Glaubenskrieg „Postgres besser als SQL Server“. Beide Engines sind ausgereift, und nicht jede Last gehört umgezogen. Der Punkt ist nüchtern: Wenn die Entscheidung gefallen ist, SQL Server nach PostgreSQL zu migrieren, lohnt es sich, den Umzug als strukturierten Pfad zu planen statt als einmalige Kopier-Aktion. Genau dafür ist dieser Leitfaden da.
Der Migrationspfad in fünf Phasen
Eine Datenbank-Migration ist kein einzelner Schritt, sondern eine Kette abhängiger Phasen. Wer sie in dieser Reihenfolge angeht, vermeidet die typischen Rückschläge — etwa Daten zu transferieren, bevor das Zielschema die richtigen Typen hat. Jede Phase hat ihren eigenen Detail-Artikel.
1. Datentypen. Die Grundlage. Die meisten Typen konvertieren eins zu eins (int, numeric, varchar, date) — aber datetime, bit, money, uniqueidentifier, nvarchar und tinyint haben keine 1:1-Entsprechung. datetime zwingt zur Zeitzonen-Frage (timestamp vs. timestamptz), bit wird zum echten boolean, vom money-Typ in Postgres lässt man besser die Finger. Welche Typen sauber konvertieren und welche kippen, klärt der Artikel Datentyp-Mapping SQL Server → PostgreSQL.
2. Schema & DDL. Hat man die Typen, kommt die Struktur drumherum: IDENTITY wird zu GENERATED AS IDENTITY oder einer Sequenz, Default-Constraints und benannte Constraints wandern um, und die Groß-/Kleinschreibung von Bezeichnern kippt von SQL-Server-tolerant zu Postgres-exakt. Details in Schema-Migration SQL Server → PostgreSQL.
3. Datentransfer. Erst wenn das Zielschema steht, wandern die Daten. Die Methodenwahl hängt von Datenmenge und Downtime-Toleranz ab: bcp-Export plus COPY, das All-in-one-Werkzeug pgloader oder eine ETL-Strecke. Welche Methode wann passt, vergleicht Daten transferieren: bcp, COPY, pgloader, ETL.
4. Code-Portierung. Tabellen sind nur die halbe Datenbank. Stored Procedures, Funktionen und Trigger müssen von T-SQL nach PL/pgSQL übersetzt werden — andere Fehlerbehandlung, andere Variablen-Syntax, andere Idiome (TRY_CONVERT hat kein direktes Gegenstück). Das ist der Teil mit dem höchsten Handarbeits-Anteil. Vertieft in T-SQL nach PL/pgSQL portieren.
5. Verifikation. Eine Migration ist erst fertig, wenn bewiesen ist, dass nichts verloren ging oder still verfälscht wurde: Zeilen-Abgleich pro Tabelle, Stichproben-Vergleiche, Datenqualitäts-Checks nach dem Load. Wie man das systematisch prüft, zeigt Migration verifizieren — Datenqualität und Zeilen-Abgleich.
Die Phasen bauen aufeinander auf, lassen sich aber iterieren — typisch ist, Typen und Schema gemeinsam an einer Pilot-Tabelle durchzuspielen, bevor die volle Last transferiert wird.
Eine Tabelle, mehrere Phasen auf einmal
Damit der Phasen-Pfad greifbar wird, eine kleine Tabelle, die mehrere Stolperfallen auf einmal bündelt. Zuerst die Quelle in T-SQL:
1: CREATE TABLE dbo.customer
2: (
3: customer_id int IDENTITY(1, 1) NOT NULL
4: ,full_name nvarchar(100) NOT NULL
5: ,is_active bit NOT NULL DEFAULT 1
6: ,created_at datetime NOT NULL DEFAULT GETDATE()
7: ,CONSTRAINT pk_customer PRIMARY KEY (customer_id)
8: );
Und dasselbe als PostgreSQL-Ziel:
1: CREATE TABLE customer
2: (
3: customer_id integer GENERATED BY DEFAULT AS IDENTITY
4: ,full_name text NOT NULL
5: ,is_active boolean NOT NULL DEFAULT true
6: ,created_at timestamp NOT NULL DEFAULT now()
7: ,CONSTRAINT pk_customer PRIMARY KEY (customer_id)
8: );
Vier Spalten, und schon greifen zwei Phasen ineinander — Datentypen und Schema — an einer Tabelle, die niemand für migrationskritisch halten würde. Drei der Änderungen sieht man kommen:
- Zeile 3 (Schema):
int IDENTITY(1, 1)→integer GENERATED BY DEFAULT AS IDENTITY— die Auto-Wert-Spalte wandert auf den SQL-Standard-Mechanismus. Die eigentliche Arbeit kommt nach dem Laden: Die Sequenz muss auf den Höchstwert nachgezogen werden, sonst kollidiert der nächsteINSERT. - Zeile 5 (Datentyp):
bit→boolean, aus1wirdtrue. Vorsicht: portierte Abfragen wieWHERE is_active = 1brechen in Postgres. - Zeile 6 (Datentyp):
datetime→timestamp. Die Falle ist nichtnow()stattGETDATE(), sondern dassdatetimekeine Zeitzone trägt: Obtimestampodertimestamptzrichtig ist, hängt davon ab, ob die Werte als lokale Zeit oder als UTC gemeint waren — trifft man die Entscheidung nicht bewusst, verschiebt sie sich später still.
Die vierte fällt beim Überfliegen durch — und rutscht am ehesten unbemerkt durch:
- Zeile 4 (Datentyp):
nvarchar(100)→text. „Postgres ist nativ Unicode, alsotext“ stimmt — verschweigt aber, dass die Längenbegrenzung verschwindet. Genau so greift ein Auto-Konverter wiepgloaderstandardmäßig zu:nvarchar(100)wird zutext, die Grenze fällt ungefragt weg. War die100nur technischer Ballast, isttextdie richtige Wahl. War sie eine fachliche Regel — die Datenbank durfte nichts Längeres annehmen —, ist eine stille Validierung verloren gegangen, und dahin gehört einvarchar(100)oder eineCHECK-Bedingung statt nacktemtext. Das Tool trifft die Übersetzung automatisch — aber ob die Grenze fachlich gewollt war, kann es nicht wissen: Diese Frage steht nicht im Typ, sondern in der Fachlichkeit.
Das ist der ganze Leitfaden in einer Tabelle: Vier Zeilen, die nach Suchen-und-Ersetzen aussehen, tragen zwei Phasen und mindestens eine Falle, die man nur sieht, wenn man die Daten fachlich kennt — nicht bloß ihren Typ.
Was Tooling abnimmt — und wo Handarbeit bleibt
Die ehrliche Erwartungssteuerung vorweg: Es gibt kein „ein Klick und fertig“. Werkzeuge wie pgloader (frei, übernimmt Schema und Daten in einem Lauf) oder kommerzielle Konverter nehmen den mechanischen Großteil ab — und das ist viel: die unkritischen Typen, der Massentransfer, die Standard-Constraints. Als Faustregel decken sie rund 80 % der Mechanik.
Die verbleibenden 20 % sind genau die Stellen, an denen eine fachliche Entscheidung nötig ist, die kein Tool kennen kann:
- Kippende Typen —
datetime→timestampodertimestamptz?money→ welchenumeric-Skala?tinyintmit erhaltenderCHECK-Bedingung? Diese Fälle gehören geprüft, nicht blind übernommen. - Prozedur- und Trigger-Logik — T-SQL nach PL/pgSQL ist Übersetzungsarbeit, kein Suchen-und-Ersetzen.
- Performance-Tuning — Indizes, Statistiken und Abfragepläne unterscheiden sich; was in SQL Server schnell war, braucht in Postgres ggf. einen anderen Index.
- Verhaltens-Unterschiede — Collation/Case, NULL-Sortierung, Transaktions-Semantik bei Fehlern.
Die Kunst der Migration liegt nicht im Transfer der einfachen 80 %, sondern in der sauberen, geprüften Übersetzung der schwierigen 20 %. Dieser Cluster widmet jeder dieser Stellen einen eigenen Artikel.
FAQ
Das hängt von Schema-Komplexität und Code-Menge ab, nicht primär von der Datenmenge. Der Datentransfer selbst ist oft in Stunden erledigt; die Zeit geht in die Code-Portierung (Stored Procedures, Trigger) und die Verifikation. Eine einfache Datenbank mit wenig Logik ist in Tagen machbar, eine mit hunderten Prozeduren in Wochen bis Monaten.
Nein. Werkzeuge wie pgloader nehmen die mechanischen ~80 % ab — die unkritischen Typen und den Massentransfer. Die letzten 20 % (kippende Typen, Prozedur-Logik, Trigger, Performance-Tuning) brauchen menschliche Entscheidungen. Wer „ein Klick und fertig“ erwartet, baut stille Fehler ein.
Sie müssen von T-SQL nach PL/pgSQL portiert werden — das ist die aufwändigste Phase. Fehlerbehandlung (TRY/CATCH → EXCEPTION), Variablen-Syntax und viele Idiome unterscheiden sich. Ein direktes Übersetzungs-Tool gibt es nicht; der eigene Artikel zur Code-Portierung zeigt die Muster.
Für die einfachste Variante (Export → Transfer → Umschalten) ja — die Quelle ist während des Transfers idealerweise read-only, damit keine Änderungen verloren gehen. Downtime-arme Strategien (logische Replikation, schrittweiser Cutover) sind möglich, aber deutlich aufwändiger und ein Thema für sich.
Für die meisten Solo- und Mittelstands-Szenarien ist der Big-Bang-Cutover in einem ruhigen Wartungsfenster pragmatisch. Schrittweise Migration (beide Systeme parallel) lohnt sich bei großen, durchgehend verfügbaren Systemen — erkauft aber mit erheblicher Synchronisations-Komplexität.
Die Phasen (Typen → Schema → Transfer → Code → Verifikation) gelten allgemein, und Azure SQL ist eng mit SQL Server verwandt — vieles überträgt sich. Dieser Cluster ist aber konkret auf SQL Server → PostgreSQL zugeschnitten; Oracle oder MySQL als Quelle bringen andere Typ- und Dialekt-Fallen mit.
Verwandte Artikel
Dieser Leitfaden ist der Überblick des Clusters zur Migration von SQL Server nach PostgreSQL. Jede Phase hat ihren eigenen Detail-Artikel:
- Datentypen: Datentyp-Mapping SQL Server → PostgreSQL — was sauber konvertiert und was kippt
- Schema & DDL: Schema-Migration SQL Server → PostgreSQL — Identity, Constraints, Defaults, Sequenzen
- Datentransfer: Daten transferieren: bcp, COPY, pgloader, ETL — welche Methode wann
- Code-Portierung: T-SQL nach PL/pgSQL portieren — Prozeduren und Funktionen migrieren
- Verifikation: Migration verifizieren — Datenqualität und Zeilen-Abgleich
Zur Vertiefung angrenzender Themen:
- Postgres-Tabellen-Konventionen — wie das Ziel-Schema idiomatisch aussieht
- ETL vs. ELT — Einordnung — Transfer-Muster und Tool-Wahl
- Datenqualität mit SQL prüfen — das Prüf-Framework für die Verifikations-Phase
- Datenqualität // Grundlagen der Typ-Konvertierung mit T-SQL — Hintergrund zu den Konvertierungs-Fallstricken