PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

PostgreSQL:Wszechstronna INSERT

Wstawienie pojedynczego wiersza do tabeli jest tym, co przychodzi na myśl, gdy myślisz o instrukcji INSERT w PostgreSQL. Ma jednak w zanadrzu kilka dodatkowych sztuczek! Czytaj dalej, aby odkryć niektóre z bardziej interesujących rzeczy, które możesz zrobić za pomocą INSERT.

Kopiowanie zbiorcze

Załóżmy, że chcesz okresowo przechwytywać migawki tabeli — wszystkie wiersze w tabeli powinny zostać skopiowane do innej tabeli z dodatkową kolumną sygnatury czasowej, wskazującą, kiedy wykonano migawkę. Oto, jak możesz utworzyć i wypełnić tabelę za pierwszym razem:

demo=# SELECT * FROM mytable;
 ticker | quote
--------+-------
 FOO    | $4.01
 BAR    | $1.42
(2 rows)

demo=# CREATE TABLE snaps_of_mytable AS
demo-#   SELECT current_timestamp AS snapped_at, *
demo-#     FROM mytable;
SELECT 2
demo=#
demo=# SELECT * FROM snaps_of_mytable ;
         snapped_at          | ticker | quote
-----------------------------+--------+-------
 2018-10-09 04:16:22.3613+00 | FOO    | $4.01
 2018-10-09 04:16:22.3613+00 | BAR    | $1.42
(2 rows)

Od tego momentu możesz używać INSERT..SELECT forma instrukcji INSERT, aby skopiować wiersze z jednej tabeli i wstawić do drugiej. Możesz również wpisać dodatkowe wartości w wierszu tabeli docelowej.

demo=# INSERT INTO snaps_of_mytable
demo-#   SELECT current_timestamp AS snapped_at, *
demo-#     FROM mytable;
INSERT 0 2
demo=#
demo=# SELECT * FROM snaps_of_mytable ;
          snapped_at           | ticker | quote
-------------------------------+--------+-------
 2018-10-09 04:16:22.3613+00   | FOO    | $4.01
 2018-10-09 04:16:22.3613+00   | BAR    | $1.42
 2018-10-09 04:18:53.432224+00 | BAR    | $1.42
 2018-10-09 04:18:53.432224+00 | FOO    | $4.10
(4 rows)

Przewrotki

W PostgreSQL 9.5, ON CONFLICT klauzula została dodana do INSERT. Pozwala to programistom aplikacji pisać mniej kodu i wykonywać więcej pracy w SQL.

Oto tabela par kluczy i wartości:

demo=# SELECT * FROM kv;
 key  |   value
------+-----------
 host | 127.0.0.1
 port | 5432
(2 rows)

Typowym przypadkiem użycia jest wstawienie wiersza tylko wtedy, gdy nie istnieje – a jeśli tak, nie nadpisuj. Odbywa się to za pomocą ON CONFLICT..DO NOTHING klauzula instrukcji INSERT:

demo=# INSERT INTO kv (key, value) VALUES ('port', '3306')
demo-# ON CONFLICT (key) DO NOTHING;
INSERT 0 0
demo=# SELECT * FROM kv;
 key  |   value
------+-----------
 host | 127.0.0.1
 port | 5432
(2 rows)

Innym powszechnym zastosowaniem jest wstawienie wiersza, jeśli nie istnieje, i zaktualizowanie wartości, jeśli tak. Można to zrobić za pomocą ON CONFLICT..DO UPDATE klauzula.

demo=# INSERT INTO kv (key, value) VALUES ('host', '10.0.10.1')
demo-# ON CONFLICT (key) DO UPDATE SET value=EXCLUDED.value;
INSERT 0 1
demo=# INSERT INTO kv (key, value) VALUES ('ssl', 'off')
demo-# ON CONFLICT (key) DO UPDATE SET value=EXCLUDED.value;
INSERT 0 1
demo=# SELECT * FROM kv;
 key  |   value
------+-----------
 host | 10.0.10.1
 port | 5432
 ssl  | off
(3 rows)

W pierwszym przypadku powyżej wartość „host” została zastąpiona nową wartością, a w drugim przypadku wartość „ssl” została wstawiona jako trzeci wiersz.

Jeszcze bardziej wyrafinowane przypadki użycia można zrealizować za pomocą DO UPDATE . Rozważ poniższą tabelę, w której oprócz klucza i wartości znajduje się kolumna o nazwie „akumuluj”. W przypadku wierszy, w których akumulacja ma wartość prawda, wartości mają być akumulowane jako ciąg oddzielony przecinkami. W przypadku innych wierszy wartości są jednowartościowe.

demo=# CREATE TABLE kv2 (
demo(#     key text PRIMARY KEY,
demo(#     accumulate boolean NOT NULL DEFAULT false,
demo(#     value text
demo(# );
CREATE TABLE
demo=# INSERT INTO kv2 VAlUES
demo-#     ('port', false, '5432'),
demo-#     ('listen', true, NULL);
INSERT 0 2
demo=# SELECT * FROM kv2;
  key   | accumulate | value
--------+------------+-------
 port   | f          | 5432
 listen | t          |
(2 rows)

WHERE Klauzula może być użyta do nadpisania kolumny „value” lub dołączyć do niej, w zależności od wartości „accumulate”, w ten sposób:

demo=# INSERT INTO kv2 AS t (key, value) VALUES ('port', '3306')
demo-# ON CONFLICT (key) DO UPDATE SET value = concat_ws(',', t.value, EXCLUDED.value)
demo-# WHERE t.accumulate;
INSERT 0 0
demo=# INSERT INTO kv2 AS t (key, value) VALUES ('listen', '127.0.0.1')
demo-# ON CONFLICT (key) DO UPDATE SET value = concat_ws(',', t.value, EXCLUDED.value)
demo-# WHERE t.accumulate;
INSERT 0 1
demo=# INSERT INTO kv2 AS t (key, value) VALUES ('listen', '10.0.10.1')
demo-# ON CONFLICT (key) DO UPDATE SET value = concat_ws(',', t.value, EXCLUDED.value)
demo-# WHERE t.accumulate;
INSERT 0 1
demo=# SELECT * FROM kv2;
  key   | accumulate |        value
--------+------------+---------------------
 port   | f          | 5432
 listen | t          | 127.0.0.1,10.0.10.1
(2 rows)

Pierwsze stwierdzenie nie skumulowało wartości „3306” do „port”, ponieważ „akumuluj” było wyłączone dla tego wiersza. Następne dwa stwierdzenia dodały wartości „127.0.0.1” i „10.0.10.1” do wartości „słuchaj”, ponieważ „akumuluj” było prawdziwe.

Zwracanie wygenerowanych wartości

Wartości generowane przez PostgreSQL podczas wstawiania, takie jak wartości domyślne lub wartości z autoinkrementacją SERIAL mogą być zwracane za pomocą RETURNING klauzula instrukcji INSERT.

Załóżmy, że musisz wygenerować losowe identyfikatory UUID jako klucze dla wierszy w tabeli. Możesz pozwolić PostgreSQL na wykonanie pracy polegającej na generowaniu identyfikatorów UUID i zwróceniu wygenerowanej wartości w ten sposób:

demo=# INSERT INTO kv (key, value) VALUES (gen_random_uuid(), 'foo') RETURNING key;
                 key
--------------------------------------
 d93ceaa5-30a8-4285-83c5-7defa79e2f90
(1 row)

INSERT 0 1
demo=# INSERT INTO kv (key, value) VALUES (gen_random_uuid(), 'bar') RETURNING key;
                 key
--------------------------------------
 caf9c5d9-9a79-4b26-877f-a75a083b0c79
(1 row)

INSERT 0 1
demo=# SELECT * FROM kv;
                 key                  | value
--------------------------------------+-------
 d93ceaa5-30a8-4285-83c5-7defa79e2f90 | foo
 caf9c5d9-9a79-4b26-877f-a75a083b0c79 | bar
(2 rows)

Przenoszenie wierszy z klauzulami CTE

Możesz nawet przenosić wiersze między tabelami za pomocą INSERT, używając WITH klauzula.Oto dwie tabele z listami rzeczy do zrobienia dla różnych lat.

demo=# SELECT * FROM todos_2018;
      what      | done
----------------+------
 thing to do #1 | t
 thing to do #2 | t
 thing to do #3 | f
(3 rows)

demo=# SELECT * FROM todos_2019;
 what | done
------+------
(0 rows)

Aby przenieść elementy do zrobienia, które nie zostały jeszcze ukończone w 2018 r. na 2019 r., możesz zasadniczo usunąć takie wiersze z tabeli 2018 i wstawić je do tabeli 2019 za jednym razem:

demo=# WITH items AS (
demo(#     DELETE FROM todos_2018
demo(#     WHERE NOT done
demo(#     RETURNING *
demo(# )
demo-# INSERT INTO todos_2019 SELECT * FROM items;
INSERT 0 1
demo=# SELECT * FROM todos_2018;
      what      | done
----------------+------
 thing to do #1 | t
 thing to do #2 | t
(2 rows)

demo=# SELECT * FROM todos_2019;
      what      | done
----------------+------
 thing to do #3 | f
(1 row)

Aby dowiedzieć się więcej o sprytnym, małym oświadczeniu INSERT, zapoznaj się z dokumentacją i eksperymentuj!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Heroku Postgres:Za dużo połączeń. Jak zabić te połączenia?

  2. PostgreSQL:Zapytanie nie ma miejsca docelowego dla danych wynikowych

  3. Psql wyświetla wszystkie tabele

  4. Funkcja Postgres zwraca tabelę nie zwraca danych w kolumnach

  5. Kiedy używać tabel dziedziczonych w PostgreSQL?