sql >> Databáze >  >> RDS >> PostgreSQL

PostgreSQL:Všestranný INSERT

Vložení jednoho řádku do tabulky je to, co vás napadne, když si vzpomenete na příkaz INSERT v PostgreSQL. Má však v rukávu několik dalších triků! Čtěte dále a objevte některé ze zajímavějších věcí, které můžete dělat s INSERT.

Hromadné kopírování

Řekněme, že chcete pravidelně pořizovat snímky tabulky – všechny řádky v tabulce by měly být zkopírovány do jiné tabulky s dodatečným sloupcem časového razítka označujícím, kdy byl snímek pořízen. Zde je návod, jak můžete vytvořit a naplnit tabulku poprvé:

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)

A od té doby můžete používat INSERT..SELECT forma příkazu INSERT zkopíruje řádky z jedné tabulky a vloží do jiné. Můžete také vyplnit další hodnoty do řádku cílové tabulky.

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)

Upserts

V PostgreSQL 9.5, ON CONFLICT klauzule byla přidána do INSERT. To umožňuje vývojářům aplikací psát méně kódu a dělat více práce v SQL.

Zde je tabulka párů klíč, hodnota:

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

Běžným případem použití je vložení řádku pouze v případě, že neexistuje – a pokud ano, nepřepisujte jej. To se provádí pomocí ON CONFLICT..DO NOTHING klauzule příkazu 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)

Dalším běžným zvykem je vložit řádek, pokud neexistuje, a aktualizovat hodnotu, pokud existuje. To lze provést pomocí ON CONFLICT..DO UPDATE doložka.

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)

V prvním případě výše byla hodnota „host“ přepsána novou hodnotou a ve druhém případě byla jako třetí řádek vložena hodnota „ssl“.

Ještě sofistikovanější případy použití lze realizovat pomocí DO UPDATE . Zvažte níže uvedenou tabulku, kde je kromě klíče a hodnoty sloupec nazvaný „kumulovat“. U řádků, kde má akumulovat hodnotu true, se mají hodnoty sčítat jako řetězec oddělený čárkami. Pro ostatní řádky jsou hodnoty jednohodnotové.

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 klauzuli lze použít k přepsání sloupce „hodnota“ nebo k němu v závislosti na hodnotě „kumulovat“ takto:

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)

První příkaz nenashromáždil hodnotu ‚3306‘ do ‚port‘, protože ‚kumulovat‘ byl pro tento řádek vypnutý. Další dva výroky přidaly hodnoty ‚127.0.0.1‘ a ‚10.0.10.1‘ do hodnoty ‚poslouchat‘, protože ‚kumulovat‘ byla pravda.

Vracející se vygenerované hodnoty

Hodnoty generované PostgreSQL během vkládání, jako jsou výchozí hodnoty nebo automaticky inkrementované SERIAL hodnoty, lze vrátit pomocí RETURNING klauzule příkazu INSERT.

Předpokládejme, že potřebujete vygenerovat náhodné UUID jako klíče pro řádky v tabulce. PostgreSQL můžete nechat, aby generoval UUID a aby vám vrátil vygenerovanou hodnotu takto:

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)

Přesouvání řádků s klauzulemi CTE

Pomocí INSERT můžete dokonce přesouvat řádky mezi tabulkami pomocí WITH clause.Zde jsou dvě tabulky se seznamy úkolů pro různé roky.

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)

Chcete-li přesunout položky úkolů, které ještě nebyly dokončeny v roce 2018, do roku 2019, můžete tyto řádky v podstatě odstranit z tabulky 2018 a vložit je do tabulky 2019 najednou:

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)

Chcete-li se dozvědět více o chytrém malém příkazu INSERT, podívejte se na dokumentaci a experimentujte!


  1. MySQL:výběr řádků, kde je sloupec prázdný

  2. Jak funguje Width_Bucket() v PostgreSQL

  3. Načítání textu UTF-8 z MySQL v R vrací ????

  4. Funkce MySQL RAND() – Generování náhodného čísla v MySQL