PostgreSQL copy table - jak kopiować dane i schemat?

Leonard Stępień .

19 marca 2026

Ekran wyboru formatu eksportu danych, w tym opcja eksportu do SQL INSERT statements, idealna do przenoszenia danych z bazy, np. PostgreSQL.
Kopiowanie tabel w PostgreSQL zwykle sprowadza się do trzech różnych operacji: przeniesienia danych do nowej tabeli, odtworzenia samej struktury albo wypełnienia już istniejącej tabeli wynikiem zapytania. Pod hasłem postgres copy table najczęściej kryją się właśnie te scenariusze, a nie jedna uniwersalna komenda. W tym artykule pokazuję, jak dobrać właściwe polecenie, czego ono nie kopiuje i jak uniknąć błędów, które przy analizie danych potrafią zaboleć najbardziej.

Najpierw wybierz, czy chcesz skopiować dane, schemat czy oba elementy naraz

  • INSERT INTO ... SELECT kopiuje dane do już istniejącej tabeli.
  • CREATE TABLE AS tworzy nową tabelę z wyniku zapytania i nadaje się do szybkich kopii danych.
  • CREATE TABLE ... LIKE jest najlepsze, gdy chcesz sklonować strukturę, a nie tylko wynik zapytania.
  • COPY służy do pracy z plikami, nie do bezpośredniego kopiowania między tabelami.
  • Przy dużych wolumenach danych najczęściej warto dodać indeksy i uruchomić ANALYZE dopiero po załadowaniu danych.

Która metoda naprawdę pasuje do zadania

W PostgreSQL nie ma jednego polecenia, które „kopiuje tabelę” w każdym sensie. Ja rozbijam ten problem na cel biznesowy, bo od tego zależy składnia, wydajność i to, czy skopiuje się tylko zawartość, czy również ograniczenia, indeksy i domyślne wartości. Dokumentacja PostgreSQL jasno pokazuje, że te operacje mają różne zastosowania, więc warto wybrać je świadomie, a nie z rozpędu.

Cel Najlepsze polecenie Co naprawdę kopiuje Na co uważać
Nowa tabela z danymi CREATE TABLE AS Wynik zapytania, czyli dane i kolumny wynikowe Nie przenosi wiernie indeksów i ograniczeń
Dopisanie danych do istniejącej tabeli INSERT INTO ... SELECT Tylko wiersze Trzeba dopasować kolumny i typy danych
Skopiowanie samej struktury CREATE TABLE ... LIKE Kolumny, typy i opcjonalnie więcej elementów schematu Nie każde INCLUDING ma sens w każdej tabeli
Import albo eksport pliku COPY lub \copy Dane między tabelą a plikiem To nie jest bezpośredni transfer tabela-tabela
Starszy styl tworzenia tabeli z wyniku SELECT INTO Nową tabelę z wyniku zapytania Jest historyczne i zwykle ustępuje CREATE TABLE AS

Jeśli masz w głowie tylko jedną rzecz, zapamiętaj to: najpierw ustal, czy potrzebujesz nowej tabeli, czy tylko dopisania rekordów do istniejącej. Od tego zależy cała reszta. Dalej pokazuję każdy wariant osobno, żeby nie mieszać tych scenariuszy ze sobą.

Jak skopiować dane do nowej tabeli

Gdy chcesz szybko stworzyć nową tabelę na podstawie istniejącej i przenieść do niej dane, najprostszy wariant to CREATE TABLE AS. To dobry wybór do snapshotów, tabel roboczych i analitycznych kopii, bo działa prosto i czytelnie. Dokumentacja PostgreSQL podaje też krótszy zapis z TABLE, który kopiuje całą zawartość źródła bez przepisywania listy kolumn.

CREATE TABLE sales_copy AS
TABLE sales;

Jeśli potrzebujesz tylko wycinka danych, lepiej od razu zbudować kopię z warunkiem lub transformacją. To szczególnie przydatne w analizie danych, gdzie zwykle nie chcesz całej tabeli, tylko fragment zamknięty w konkretnym przedziale czasu albo zestaw rekordów spełniających warunek biznesowy.

CREATE TABLE sales_2026_q1 AS
SELECT id, customer_id, amount, created_at
FROM sales
WHERE created_at >= DATE '2026-01-01'
  AND created_at < DATE '2026-04-01';

Warto pamiętać, że taka kopia jest jednorazowym wynikiem zapytania. Nowa tabela nie śledzi potem zmian w źródle. To zaleta, jeśli budujesz punkt w czasie do raportu, ale wada, jeśli oczekujesz automatycznej synchronizacji. Właśnie dlatego ten wariant tak dobrze pasuje do zadań analitycznych, a gorzej do pełnej repliki operacyjnej. Jeśli potrzebujesz pustej tabeli o tej samej budowie, przechodzę do następnego wariantu.

Jak odtworzyć samą strukturę bez danych

Jeżeli chcesz sklonować tabelę, ale bez rekordów, najbardziej precyzyjnym narzędziem jest CREATE TABLE ... LIKE. To rozwiązanie daje większą kontrolę niż tworzenie tabeli z wyniku zapytania, bo możesz zdecydować, które elementy schematu mają zostać przeniesione. W praktyce to mój pierwszy wybór dla tabel stagingowych, tymczasowych i pomocniczych.

CREATE TABLE sales_archive (
  LIKE sales INCLUDING ALL
);

Opcja INCLUDING ALL jest wygodna, ale nie zawsze optymalna. Czasem lepiej świadomie wybrać tylko część elementów:

  • INCLUDING DEFAULTS przydaje się, gdy chcesz zachować domyślne wartości kolumn.
  • INCLUDING IDENTITY kopiuje definicję kolumn autoinkrementowanych, ale tworzy nową sekwencję dla nowej tabeli.
  • INCLUDING INDEXES ma sens wtedy, gdy naprawdę chcesz wierny klon, a nie lekką tabelę roboczą.
  • INCLUDING CONSTRAINTS przenosi ograniczenia CHECK, a NOT NULL i tak jest kopiowane.

Jest tu jeden detal, który łatwo przeoczyć: jeśli domyślna wartość korzysta z funkcji typu nextval, to kopiowanie defaultów może tworzyć niezamierzone powiązanie między starą i nową tabelą. To nie jest błąd samego mechanizmu, tylko sygnał, że przy klonowaniu schematu trzeba patrzeć nie tylko na kolumny, ale też na logikę ich wartości. Gdy struktura jest już gotowa, naturalnym kolejnym krokiem staje się wypełnienie jej danymi.

Jak przepisać dane do istniejącej tabeli

Jeśli tabela docelowa już istnieje, najczęściej używam INSERT INTO ... SELECT. To najbardziej bezpośredni sposób kopiowania rekordów między tabelami, a jednocześnie najbardziej elastyczny. Możesz wskazać tylko część kolumn, zmienić ich kolejność, zrobić rzutowanie typów albo od razu przefiltrować dane.

INSERT INTO sales_archive (id, customer_id, amount, created_at)
SELECT id, customer_id, amount, created_at
FROM sales
WHERE status = 'paid';

Ten wariant jest bezpieczniejszy niż SELECT *, bo nie zakłada identycznego układu kolumn po obu stronach. W praktyce to ważne nawet wtedy, gdy dziś schematy są takie same, bo w kolejnej iteracji projektu ktoś doda kolumnę, zmieni kolejność albo wprowadzi kolumnę generowaną. Ja wolę dopisać listę pól raz, a potem mieć spokój.

INSERT INTO sales_archive (customer_id, amount_pln, copied_at)
SELECT customer_id, amount * 4.05, NOW()
FROM sales
WHERE created_at >= CURRENT_DATE - INTERVAL '30 days';

To właśnie tutaj najlepiej widać przewagę INSERT ... SELECT: nie tylko kopiujesz, ale od razu przekształcasz dane pod konkretny model analityczny. Jeśli chcesz uniknąć duplikatów, możesz też połączyć ten wzorzec z ON CONFLICT, ale sens takiego kroku zależy już od kluczy i reguł biznesowych w tabeli docelowej. Następny temat warto wyjaśnić osobno, bo bywa mylony z kopiowaniem tabel częściej niż wszystkie pozostałe.

Dlaczego COPY działa inaczej niż wiele osób zakłada

Tu najczęściej pojawia się nieporozumienie: COPY nie kopiuje tabeli do tabeli. Według dokumentacji PostgreSQL ten mechanizm przenosi dane między tabelą a plikiem w systemie plików. COPY TO eksportuje dane, a COPY FROM je importuje i dokleja do istniejącej tabeli.

COPY sales TO '/tmp/sales.csv' WITH (FORMAT csv, HEADER true);
COPY sales_import FROM '/tmp/sales.csv' WITH (FORMAT csv, HEADER true);

To rozwiązanie ma sens, gdy pracujesz z CSV, hurtowym importem albo eksportem na potrzeby integracji. Jest też bardzo szybkie przy dużych wolumenach, ale działa najlepiej w swoim właściwym środowisku: najpierw tworzysz tabelę, potem ładujesz dane, a dopiero na końcu budujesz indeksy. Gdy dane mają trafić z jednego wyniku SQL do drugiej tabeli w tej samej bazie, ja sięgam po INSERT INTO ... SELECT albo CREATE TABLE AS, nie po COPY. To oszczędza czas i usuwa pokusę, żeby klikać dookoła problemu zamiast rozwiązać go wprost.

Najczęstsze błędy przy duplikowaniu tabel

Przy kopiowaniu tabel problemy zwykle nie wynikają z samej składni, tylko z tego, że ktoś oczekuje od polecenia czegoś, czego ono nie robi. W praktyce widzę kilka powtarzalnych błędów:

  • Zakładanie, że CREATE TABLE AS skopiuje indeksy i ograniczenia. Nie skopiuje ich w pełnym sensie schematu; dostajesz nową tabelę opartą o wynik zapytania.
  • Używanie SELECT * między tabelami o innym schemacie. To działa tylko wtedy, gdy układ i typy kolumn naprawdę się zgadzają.
  • Zapominanie o kolumnach generowanych i identity. W takich tabelach warto jawnie wskazać listę kolumn zamiast liczyć na automatyzm.
  • Próba użycia COPY do kopiowania między dwiema tabelami. To narzędzie od plików, nie od bezpośredniej replikacji SQL.
  • Załadowanie wielkiej ilości danych z aktywnymi indeksami i kluczami obcymi. Przy dużych wsadach to spowalnia operację bardziej, niż większość osób zakłada.
  • Brak ANALYZE po dużym załadunku. Bez aktualnych statystyk planner może wybrać gorszy plan zapytania.

Ten ostatni punkt jest szczególnie ważny w analizie danych. Tabela może być poprawnie skopiowana, a mimo to raporty po uruchomieniu działają wolniej, bo optymalizator nie zna jeszcze rozkładu wartości. Właśnie dlatego samo skopiowanie danych to dopiero połowa zadania.

Jak ja wybieram metodę przy analizie danych i migracjach

Jeżeli mam zbudować tabelę roboczą do analizy, zwykle idę najkrótszą drogą: CREATE TABLE AS, potem ewentualnie indeksy i na końcu ANALYZE. Jeśli mam odtworzyć strukturę do ładowania danych, wybieram CREATE TABLE ... LIKE, bo wtedy kontroluję schemat od początku. Gdy dokładam rekordy do tabeli już używanej przez aplikację lub raport, zostaję przy INSERT INTO ... SELECT. To prosta reguła, ale w praktyce oszczędza sporo błędów.

Dokumentacja PostgreSQL podpowiada też, że przy dużych importach najszybciej działa układ: utworzyć tabelę, załadować dane masowo, a dopiero później zbudować indeksy i odświeżyć statystyki. W projektach analitycznych to zwykle lepsze niż próba utrzymania wszystkiego w pełnej gotowości od pierwszej sekundy, bo zmniejsza narzut i przyspiesza cały proces.

Jeśli mam zostawić jedną praktyczną wskazówkę, to tę: nie kopiuj „tabeli” jako idei, tylko konkretny element, którego naprawdę potrzebujesz. Czasem chodzi o dane, czasem o schemat, a czasem o jednorazowy eksport do pliku. Gdy to rozdzielisz, SQL w PostgreSQL staje się prostszy, czytelniejszy i zwyczajnie bezpieczniejszy.

FAQ - Najczęstsze pytania

Użyj `INSERT INTO ... SELECT` do przeniesienia danych do istniejącej tabeli. Jeśli chcesz stworzyć nową tabelę z danymi, najlepsze będzie `CREATE TABLE AS SELECT`. Pamiętaj, aby dopasować kolumny i typy danych.
`CREATE TABLE AS` tworzy nową tabelę z wynikami zapytania, kopiując dane i kolumny, ale bez indeksów i ograniczeń. `CREATE TABLE ... LIKE` klonuje samą strukturę tabeli (kolumny, typy, opcjonalnie indeksy, ograniczenia), ale bez danych.
`COPY` służy do importowania lub eksportowania danych między tabelą a plikiem (np. CSV) w systemie plików. Nie jest to narzędzie do bezpośredniego kopiowania danych między dwiema tabelami w bazie. Jest szybkie przy dużych wolumenach danych.
Nie, `CREATE TABLE AS` nie kopiuje indeksów, kluczy obcych ani większości ograniczeń (poza `NOT NULL`). Tworzy nową tabelę opartą wyłącznie na wyniku zapytania. Jeśli potrzebujesz klonowania schematu z tymi elementami, użyj `CREATE TABLE ... LIKE INCLUDING ALL`.
Oceń artykuł

Średnia: 0.0 / 5 · 0 ocen

Tagi

postgres copy table postgresql copy table kopiowanie tabel postgresql
Autor Leonard Stępień
Leonard Stępień
Nazywam się Leonard Stępień i od 8 lat zajmuję się tematyką technologii, sztucznej inteligencji oraz zarządzania projektami. Moje zainteresowanie tymi dziedzinami zaczęło się w czasach studiów, kiedy odkryłem, jak ogromny wpływ nowoczesne technologie mają na nasze życie i sposób pracy. Lubię dzielić się wiedzą na temat najnowszych trendów oraz praktycznych rozwiązań, które mogą pomóc innym w codziennych wyzwaniach. W moich tekstach skupiam się na jasnym i zrozumiałym przedstawianiu skomplikowanych zagadnień, starając się dostarczać rzetelne i aktualne informacje. Zawsze sprawdzam źródła i porównuję różne perspektywy, aby zapewnić czytelnikom pełny obraz omawianych tematów. Wierzę, że dobrze zorganizowana wiedza jest kluczem do efektywnego zarządzania projektami i wykorzystania potencjału sztucznej inteligencji w biznesie.
Komentarze (0)
Dodaj komentarz