sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL:de veelzijdige INSERT

Het invoegen van een enkele rij in een tabel is wat in je opkomt als je denkt aan de INSERT-instructie in PostgreSQL. Het heeft echter nog een paar trucjes in petto! Lees verder om enkele van de interessantere dingen te ontdekken die u kunt doen met INSERT.

In bulk kopiëren

Stel dat u periodiek snapshots van een tabel wilt vastleggen - alle rijen in de tabel moeten naar een andere tabel worden gekopieerd, met een extra tijdstempelkolom die aangeeft wanneer de snapshot is gemaakt. Hier leest u hoe u de tabel de eerste keer kunt maken en vullen:

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)

En vanaf dat moment kunt u de INSERT..SELECT . gebruiken vorm van INSERT-instructie om rijen van de ene tabel te kopiëren en in een andere in te voegen. U kunt ook extra waarden invullen in de rij van de bestemmingstabel.

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

In PostgreSQL 9.5, de ON CONFLICT clausule is toegevoegd aan INSERT. Hierdoor kunnen applicatieontwikkelaars minder code schrijven en meer werk doen in SQL.

Hier is een tabel met sleutel-, waardeparen:

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

Een veelvoorkomend gebruik is om een ​​rij alleen in te voegen als deze niet bestaat - en als dat wel het geval is, overschrijf dan niet. Dit doe je met de ON CONFLICT..DO NOTHING clausule van de INSERT-instructie:

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)

Een ander veelgebruikt gebruik is om een ​​rij in te voegen als deze niet bestaat, en de waarde bij te werken als dat wel het geval is. Dit kan met de ON CONFLICT..DO UPDATE clausule.

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)

In het eerste geval hierboven werd de waarde van 'host' overschreven met de nieuwe waarde, en in het tweede geval werd de waarde van 'ssl' ingevoegd als de derde rij.

Met DO UPDATE kunnen nog geavanceerdere gebruiksscenario's worden gerealiseerd . Beschouw de onderstaande tabel, waar naast sleutel en waarde, er een kolom is met de naam "accumuleren". Voor rijen waar accumuleren waar is, zijn de waarden bedoeld om te worden geaccumuleerd als een door komma's gescheiden tekenreeks. Voor andere rijen zijn waarden enkelvoudig.

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)

De WHERE clausule kan worden gebruikt om ofwel de kolom "waarde" te overschrijven, of erin toe te voegen, afhankelijk van de waarde van "accumuleren", als volgt:

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)

De eerste instructie heeft de waarde van '3306' niet geaccumuleerd in 'poort' omdat 'accumuleren' was uitgeschakeld voor die rij. De volgende twee uitspraken voegden de waarden '127.0.0.1' en '10.0.10.1' toe aan de waarde van 'luisteren', omdat 'accumuleren' waar was.

Gegenereerde waarden retourneren

Waarden gegenereerd door PostgreSQL tijdens het invoegen, zoals standaardwaarden of automatisch verhoogde SERIAL-waarden kunnen worden geretourneerd met de RETURNING clausule van de INSERT-instructie.

Stel dat u willekeurige UUID's moet genereren als sleutels voor rijen in een tabel. U kunt PostgreSQL het werk van het genereren van de UUID's laten doen en de gegenereerde waarde als volgt naar u laten terugsturen:

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)

Rijen verplaatsen met CTE-clausules

U kunt zelfs rijen tussen tabellen verplaatsen met INSERT, met behulp van de WITH clausule.Hier zijn twee tabellen met takenlijsten voor verschillende jaren.

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)

Om de todo-items die nog niet zijn voltooid in 2018 naar 2019 te verplaatsen, kunt u dergelijke rijen in principe in één keer uit de tabel van 2018 verwijderen en invoegen in de 2019-tabel:

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)

Bekijk de documentatie en experimenteer voor meer informatie over de slimme kleine INSERT-instructie!


  1. MySQL Split-Brain elimineren in multi-clouddatabases

  2. Een C#-lijst in een database invoegen met Dapper.NET

  3. Hoe de REGEXP_INSTR()-functie werkt in MySQL

  4. Hoe selecteer ik alle kolommen uit een tabel, plus extra kolommen zoals ROWNUM?