SQL

Jak, jednym INSERT w SQL, wstawić do bazy danych wiele rekordów?

Wielorekordowy INSERT w SQL

Jeśli używasz SQL i komendy INSERT aby wstawiać, do bazy danych, duże ilości danych to pokażę Ci jak robić to wydajniej. Dostępne w wielu motorach baz danych. Na przykład PostgreSQL, SQL Server, MySQL, MariaDB i Oracle.

Publikacja w formie wideo
Klasyczne podejście

Jeśli, więc do tej pory pracowicie konstruujesz pętle budując sekwencje komend SQL wyglądające jak ta:

INSERT INTO tabela (kol1, kol2) VALUES (11,12);
INSERT INTO tabela (kol1, kol2) VALUES (21,22);
INSERT INTO tabela (kol1, kol2) VALUES (31,32);

i masz dość powtarzania 'INSERT INTO … VALUES’ za każdym razem. To zmień podejście na wydajniejsze. Przy okazji zaoszczędzisz czas potrzebny na napisanie wielu powtarzalnych klauzul.

Zbiorowy INSERT w SQL

Motory baz danych operują na zbiorach danych. Są do tego zaprojektowane. Nie jest, więc zaskoczeniem, że masowe operacje są wydajniejsze niż wiele pojedynczych. W ten trend wpisuje się wielorekordowy INSERT.

Pojawił się w standardzie SQL-92 jako 'row value constructors’. Znany również jako 'table value constructor’.

Potrafi znacząco skrócić czas potrzebny na załadowanie danych. Zużywa mniej zasobów motoru bazy danych. Wykonuje także mniej komunikacji sieciowej klient<->instancja bazy danych.

Szczególnie istotne jeśli płacisz za transfer sieciowy i CPU hosta z bazą danych. Na przykład dostawcy chmury.

Wiele komend INSERT w jednej transakcji

UWAGA! Zamykanie wielu pojedynczych komend INSERT w jednej transakcji w taki sposób:

BEGIN TRANSACTION;
INSERT INTO tabela (kol1, kol2) VALUES (11,12);
INSERT INTO tabela (kol1, kol2) VALUES (21,22);
COMMIT;

NIE jest równoznaczne z wielorekordowym INSERT. W dalszym ciągu każda z komend jest osobno parsowana, miejsce na dane osobno alokowane, a indeksy osobno modyfikowane.

Jak wstawić wiele rekordów w PostgreSQL, SQL Server, MySQL, MariaDB i Oracle od wersji 23ai?

W PostgreSQL, SQL Server, MySQL, MariaDB i Oracle 23ai wstawiasz wiele rekordów przy pomocy jednej komendy INSERT w taki sposób:

INSERT INTO tabela (kol1, kol2) VALUES -- pojedyncza komenda INSERT
(1,1)   -- rekord 1
,(2,2)  -- rekord 2
,(3,3); -- rekord 3

SQL Server ma limit 1000 rekordów, które jest w stanie wstawić jedną komendą SQL.

W klauzuli VALUES musisz zawsze podać tyle wartości ile kolumn specyfikujesz w klauzuli INTO. W przypadku gdy wstawiasz rekordy bez wszystkich wartości, możesz bazować na, zdefiniowanych dla kolumny, wartościach domyślnych. Lub Wstawić NULL. Robisz to tak:

INSERT INTO tabela (kol1,kol2) VALUES
(DEFAULT,2)
,(11,22)
,(21,NULL);

Powyższa składnia nie pozwala na użycie podzapytań zwracających więcej niż pojedynczą wartość. Można to obejść w taki sposób:

INSERT INTO tabela1 (kol1, kol2) VALUES
(11,12)
,(21,22)
,((SELECT kol1 FROM tabela2 WHERE id=321), (SELECT kol2 FROM tabela2 WHERE id=321));
Jak wstawić wiele rekordów w Oracle pre 23ai?

Oracle ma inną składnię niż zaprezentowana powyżej. Wygląda tak:

INSERT ALL
  INTO tabela (kol1, kol2) VALUES (1,1)
  INTO tabela (kol1, kol2) VALUES (2,2)
  INTO tabela (kol1, kol2) VALUES (3,3)
SELECT * FROM dual;

Sposób Oracle ma taką zaletę, że jedną komendą INSERT, możesz wstawiać wiele rekordów do wielu tabel jednocześnie. Na przykład tak:

INSERT ALL
  INTO tabela1 (kol11, kol12) VALUES (11,12)
  INTO tabela2 (kol21, kol22) VALUES (21,22)
  INTO tabela3 (kol31, kol32) VALUES (31,32)
SELECT * FROM dual;
COMMIT;

Jest to wielotabelowy INSERT. Choć funkcjonalnie realizuje te same cele – umożliwia wstawienie wielu rekordów jedną komendą.

Przetestuj to na swojej bazie danych tworząc 3 tabele:

CREATE TABLE tabela1(
  kol11 number(2)
  ,kol12 number(2)
);
CREATE TABLE tabela2(
  kol21 number(2)
  ,kol22 number(2)
);
CREATE TABLE tabela3(
  kol31 number(2)
  ,kol32 number(2)
);

A następnie wykonaj poprzedni INSERT ALL nie zapominając o COMMIT. I sprawdź czy dane zostały wstawione:

SELECT * FROM tabela1
UNION ALL
SELECT * FROM tabela2
UNION ALL
SELECT * FROM tabela3;

Jak wszystko poszło smukle to zobaczysz taki wynik w SQL Developerze:

Wynik komendy SELECT

Umożliwia również wstawianie warunkowe. Ale to już temat na osobny wpis.

Składnia Oracle ma swoje limity. Nie są one jednak sprecyzowane jedną liczbą. Jest to iloczyn liczby kolumn tabeli docelowej i liczby klauzul INTO w komendzie INSERT ALL. Wg terminologii Oracle jest to multi-table INSERT.

Wielorekordowy INSERT to wszystko albo nic

Wielorekordowy INSERT reprezentuje podejście wszystko albo nic. Czyli albo powiedzie się wstawienie wszystkich rekordów wymienionych w komendzie INSERT, albo żaden z rekordów nie zostanie wstawiony. Warto mieć to na uwadze.

Gdy zależy Ci na innym podejściu – na przykład na rozwiązywaniu konfliktów lub zamianie INSERT na UPDATE – rozważ komendę MERGE. Będę o tym pisał w następnym wpisie.

Artykuł o podstawach komendy INSERT języka SQL: Podstawy INSERT w SQL. Dotyczy Oracle, PostgreSQL, MySQL i SQL Server.

Artykuł o tym jak najszybciej wstawić do bazy danych jak największą ilość rekordów zużywając jak najmniej zasobów instancji: Jak efektywnie wstawić wiele rekordów do tabeli wykorzystując SQL?. Wszystko przy pomocy SQL i języków proceduralnych na przykładzie Oracle i PostgreSQL.

Artykuł o tym jak komendą INSERT języka SQL wstawić do bazy danych dane typu znakowego, numerycznego i datoczasowego: Jak dodać rekord do tabeli? Komenda INSERT języka SQL. Na przykładzie bazy danych Oracle.

Prowadzę szkolenia i kursy z podstaw SQL. Sprawdź ofertę moich kursów SQL.

Marcin Badtke

Przyjaźnie o SQL, bazach danych i ludziach

Może Ci się spodobać...

4 Comments

  1. Bardzo fajny wpis. Tylko jedna, kosmetyczna uwaga: zawsze używałem zwrotu silnik bazy danach (database engine) a nie motor bazy danych i brzmi on dla mnie bardziej naturalnie.

    1. Marcin Badtke

      Dzięki 🙂

  2. Zbigniew Heintze

    W artykule warto by poruszyć jeszcze kwestie lock-owania tabel w trakcie wykonywania bulk insertów a także możliwości przyspieszania tej operacji np. poprzez tymczasowe usuwanie indeksów

    1. Marcin Badtke

      Dzięki za podpowiedź. Sądzę, że to dobry temat na osobny wpis.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *