sql >> Database >  >> RDS >> PostgreSQL

Hoe kan ik geselecteerde rijen bijwerken met waarden uit een CSV-bestand in Postgres?

COPY het bestand naar een tijdelijke staging-tabel en werk de eigenlijke tabel vanaf daar bij. Vind ik leuk:

CREATE TEMP TABLE tmp_x (id int, apple text, banana text); -- but see below

COPY tmp_x FROM '/absolute/path/to/file' (FORMAT csv);

UPDATE tbl
SET    banana = tmp_x.banana
FROM   tmp_x
WHERE  tbl.id = tmp_x.id;

DROP TABLE tmp_x; -- else it is dropped at end of session automatically

Als de geïmporteerde tabel exact overeenkomt met de tabel die moet worden bijgewerkt, kan dit handig zijn:

CREATE TEMP TABLE tmp_x AS SELECT * FROM tbl LIMIT 0;

Creëert een lege tijdelijke tabel die overeenkomt met de structuur van de bestaande tabel, zonder beperkingen.

Voorrechten

Tot Postgres 10, SQL COPY vereist hiervoor superuser-privileges.
In Postgres 11 of later zijn er ook enkele vooraf gedefinieerde rollen (voorheen "standaardrollen") om dit toe te staan. De handleiding:

COPY het benoemen van een bestand of commando is alleen toegestaan ​​voor database superusers of gebruikers die een van de rollen hebben gekregen pg_read_server_files ,pg_write_server_files , of pg_execute_server_program [...]

De psql meta-commando \copy werkt voor elke db-rol. De handleiding:

Voert een frontend (client) kopie uit. Dit is een bewerking die eenSQL COPY . uitvoert commando, maar in plaats van dat de server het gespecificeerde bestand leest of schrijft, leest of schrijft psql het bestand en routeert de gegevens tussen de server en het lokale bestandssysteem. Dit betekent dat bestandstoegankelijkheid en privileges die van de lokale gebruiker zijn, niet van de server, en er zijn geen SQL-superuser-privileges vereist.

Het bereik van tijdelijke tabellen is beperkt tot een enkele sessie van een enkele rol, dus het bovenstaande moet in dezelfde psql-sessie worden uitgevoerd:

CREATE TEMP TABLE ...;
\copy tmp_x FROM '/absolute/path/to/file' (FORMAT csv);
UPDATE ...;

Als je dit script in een bash-commando schrijft, zorg er dan voor dat je het allemaal in een enkele verpakt psql-oproep. Vind ik leuk:

echo 'CREATE TEMP TABLE tmp_x ...; \copy tmp_x FROM ...; UPDATE ...;' | psql

Normaal gesproken heb je het meta-commando \\ . nodig om te schakelen tussen psql-metacommando's en SQL-commando's in psql, maar \copy vormt een uitzondering op deze regel. Nogmaals de handleiding:

speciale parseerregels zijn van toepassing op de \copy meta-opdracht. In tegenstelling tot de meeste andere meta-commando's, wordt de hele rest van de regel altijd beschouwd als de argumenten van \copy , en er worden geen variabele interpolatie of backquote-expansie uitgevoerd in de argumenten.

Grote tafels

Als de importtabel groot is, kan het lonen om temp_buffers te verhogen tijdelijk voor de sessie (eerste in de sessie):

SET temp_buffers = '500MB';  -- example value

Voeg een index toe aan de tijdelijke tabel:

CREATE INDEX tmp_x_id_idx ON tmp_x(id);

En voer ANALYZE uit handmatig, aangezien tijdelijke tabellen niet worden gedekt door autovacuum / auto-analyse.

ANALYZE tmp_x;

Gerelateerde antwoorden:

  • De beste manier om miljoenen rijen op ID te verwijderen
  • Hoe kan ik algemene gegevens uit verschillende schema's in een tijdelijke tabel invoegen?
  • Hoe verwijder ik dubbele vermeldingen?


  1. pdo voorbereide uitspraken met jokertekens

  2. Selecteer TOP X (of onderste) procent voor numerieke waarden in MySQL

  3. Ongestructureerde inhoud:een onaangeboorde brandstofbron voor AI en machine learning

  4. Meest efficiënte manier om het aantal rijen in de tabel te krijgen