sql >> Database teknologi >  >> RDS >> PostgreSQL

Mine foretrukne PostgreSQL-forespørgsler og hvorfor de betyder noget

Databaser, tabeller, normalisering og en solid backup-plan giver os mulighed for at gemme og vedligeholde data.

Disse kombinerede bedste praksis giver os til gengæld interaktion med disse data. I nutidens datadrevne verden er data værdifulde. Ikke kun værdifulde, data er ofte kritiske for slutbrugerløsninger leveret af produkter og tjenester. Uddrag af indsigt, besvarelse af spørgsmål og meningsfulde metrics fra data ved hjælp af forespørgsler og datamanipulation er en integreret komponent af SQL generelt.

PostgreSQL er ikke anderledes.

Dette grundlæggende kernepunkt er afgørende for succes i ethvert datadrevet aspekt.

Nedenfor præsenterer jeg en kombination af 8 forskellige forespørgsler eller typer forespørgsler, som jeg har fundet interessante og engagerende at udforske, studere, lære eller på anden måde manipulere med datasæt.

De er ikke opført i nogen rækkefølge af betydning.

De fleste vil nok være kendte gamle venner. Måske bliver nogle nye bekendtskaber.

Eksempeltabeller og anvendte data er ikke så vigtige som selve konstruktionen af ​​forespørgslerne, og hvad hver forespørgsel returnerer, tilbyder eller giver. Mange af dem er hånlige og afledt til demonstrationsformål og bør ikke tages bogstaveligt i deres værdier.

1. Venstre join, pas på eventuelle nuller til højre...

Antag, at vi i dette eksempel har et løbende salg på to måneder og får begge dele samlet.

Alligevel trak den anden måned af en eller anden grund ikke sit vægt, og vi ønsker at målrette, hvilke dage i måneden, hvor der blev taget fat.

Disse salg er repræsenteret som tabeller betaling og fake_month for denne demonstration.

Bemærk:

  • Vi kontrollerer kun for totaler på over 2000.
  • Vi begrænser outputtet til kun 10 rækker.

Til at starte med har vi dette Common Table Expression (CTE) 'generering ' fake_month-tabellen for os, og den forespørgsel, der følger.

dvdrental=> WITH fake_month AS(
SELECT setup::date
FROM generate_series('2007-02-01', '2007-02-28', INTERVAL '1 day') AS setup
)
SELECT date_part('day', p.payment_date)::INT AS legit,
SUM(p.amount),
date_part('day', fk.setup)::INT AS fake
FROM payment AS p
LEFT JOIN fake_month AS fk
ON date_part('day', fk.setup)::INT = date_part('day', p.payment_date)::INT
GROUP BY legit, fake
HAVING SUM(p.amount) > 2000
LIMIT 10;
legit | sum | fake
-------+---------+------
1 | 2808.24 | 1
2 | 2550.05 | 2
6 | 2077.14 | 6
8 | 2227.84 | 8
9 | 2067.86 | 9
17 | 3630.33 | 17
18 | 3977.74 | 18
19 | 3908.59 | 19
20 | 3888.98 | 20
21 | 3786.14 | 21
(10 rows)

Det ser ud til, at begge måneder har bidraget dertil. Så er dette løst?

Før vi betragter dette som løst, lad os besøge ORDER BY-klausulen.

Du kan selvfølgelig BESTILLE MED ASC eller DESC.

Du kan dog også BESTILLE EFTER NUL først eller sidst, og det ændrer tingene lidt.

Lad os omskrive denne forespørgsel og bruge ORDER BY NULLS først i den lovlige kolonne.

For kortheds skyld fjerner jeg CTE'en fra outputtet, bare ved at den stadig er der og bliver brugt.

SELECT date_part('day', p.payment_date)::INT AS legit,
SUM(p.amount),
date_part('day', fk.setup)::INT AS fake
FROM payment AS p
LEFT JOIN fake_month AS fk
ON date_part('day', fk.setup)::INT = date_part('day', p.payment_date)::INT
GROUP BY legit, fake
HAVING SUM(p.amount) > 2000
ORDER BY legit NULLS first
LIMIT 10;
legit | sum | fake
-------+---------+------
1 | 2808.24 | 1
2 | 2550.05 | 2
6 | 2077.14 | 6
8 | 2227.84 | 8
9 | 2067.86 | 9
17 | 3630.33 | 17
18 | 3977.74 | 18
19 | 3908.59 | 19
20 | 3888.98 | 20
21 | 3786.14 | 21
(10 rows)

Ingen forskel der overhovedet.

Hvad hvis vi BESTILLER EFTER NUL først på den falske kolonne? Den til højre side af JOIN?

Lad os se.

SELECT date_part('day', p.payment_date)::INT AS legit,
SUM(p.amount),
date_part('day', fk.setup)::INT AS fake
FROM payment AS p
LEFT JOIN fake_month AS fk
ON date_part('day', fk.setup)::INT = date_part('day', p.payment_date)::INT
GROUP BY legit, fake
HAVING SUM(p.amount) > 2000
ORDER BY fake NULLS first
LIMIT 10;
legit | sum | fake
-------+---------+------
29 | 2717.60 |
30 | 5723.89 |
1 | 2808.24 | 1
2 | 2550.05 | 2
6 | 2077.14 | 6
8 | 2227.84 | 8
9 | 2067.86 | 9
17 | 3630.33 | 17
18 | 3977.74 | 18
19 | 3908.59 | 19
(10 rows)

Nu er vi på vej et sted hen. Vi kan se for dag 29 og 30, at den falske kolonne er blevet bestilt fra toppen af ​​resultatsættet.

På grund af BESTILLING AF falske NULLER først.

Dette løser vores spørgsmål, til hvilke dage 'udsalg 2' slap af.

Undrer du dig...

"Kan vi bare filtrere med WHERE fake IS NULL? "

Sådan:

SELECT date_part('day', p.payment_date)::INT AS legit,
SUM(p.amount),
date_part('day', fk.setup)::INT AS fake
FROM payment AS p
LEFT JOIN fake_month AS fk
ON date_part('day', fk.setup)::INT = date_part('day', p.payment_date)::INT
WHERE date_part('day', fk.setup) IS NULL
GROUP BY legit, fake
HAVING SUM(p.amount) > 2000
LIMIT 10;
legit | sum | fake
-------+---------+------
29 | 2717.60 |
30 | 5723.89 |
(2 rows)

Ja det virker. Så hvorfor ikke bare bruge den forespørgsel i stedet for? Hvorfor betyder det noget?

Jeg føler, at det at bruge LEFT JOIN og ORDER BY NULLS først til tabellen i højre side af JOIN, er en fantastisk måde at udforske ukendte tabeller og datasæt.

Ved at bekræfte, hvilke data der eventuelt "mangler ’ på den side af sammenføjningsbetingelsen først; øger klarheden og bevidstheden, så du kan filtrere resultaterne fra med WHERE IS NULL-sætningen, og afslutte tingene.

Selvfølgelig kan kendskab til tabellerne og datasættene potentielt eliminere behovet for LEFT JOIN, der præsenteres her.

Det er en værdig forespørgsel for alle, der bruger PostgreSQL til i det mindste at prøve under udforskning.

2. Strengsammenkædning

Sammenkædning, sammenføjning eller tilføjelse af to strenge, giver en præsentationsmulighed for resultatsæt. Mange 'ting ' kan sammenkædes.

Som nævnt i dokumentationen accepterer strengsammenkædningsoperatoren ('||') dog ikke-streng input, så længe en er en streng.

Lad os se nogle eksempler med nedenstående forespørgsler:

postgres=> SELECT 2||' times'||' 2 equals: '|| 2*2;
?column?
---------------------
2 times 2 equals: 4
(1 row)

Vi kan se, tal og strenge kan alle sammenkædes som nævnt ovenfor.

'||' operator er kun en af ​​dem, der er tilgængelige i PostgreSQL.

Concat()-funktionen accepterer flere argumenter og sammenkæder dem alle ved returnering.

Her er et eksempel på den funktion i aktion:

postgres=> SELECT concat('Josh ','Otwell') AS first_name;
first_name
-------------
Josh Otwell
(1 row)

Vi kan sende mere end to argumenter, hvis det ønskes:

postgres=> SELECT concat('Josh',' ','Otwell') AS first_name;
first_name
-------------
Josh Otwell
(1 row)

Lad os bemærke noget rigtig hurtigt med disse næste eksempler:

postgres=> SELECT CONCAT('Josh',NULL,'Otwell') AS first_name;
first_name
------------
JoshOtwell
(1 row)
postgres=> SELECT 'Josh '||NULL||'Otwell' AS first_name;
first_name
------------
(1 row)
postgres=> SELECT NULL||'Josh '||'Otwell' AS first_name;
first_name
------------
(1 row)
postgres=> SELECT CONCAT(NULL,'Josh','Otwell') AS first_name;
first_name
------------
JoshOtwell
(1 row)

Bemærk, at concat()-funktionen ignorerer NULL, uanset hvor den placeres på listen over parametre, mens strengsammenkædningsoperatoren ikke gør det.

NULL returneres, hvis den findes et hvilket som helst sted i strengen for at sammenkæde.

Bare vær opmærksom på det.

I stedet for manuelt at inkludere i strengen, der skal sammenkædes, inkluderer PostgreSQL også en concat_ws() funktion, der accepterer en strengseparator som den første parameter.

Vi vil besøge det med disse forespørgsler:

postgres=> SELECT concat_ws('-',333,454,1919) AS cell_num;
cell_num
--------------
333-454-1919
(1 row)
postgres=> SELECT concat_ws(' ','Josh','Otwell') AS first_name;
first_name
-------------
Josh Otwell
(1 row)

concat_ws() accepterer enten tal eller strenge som argumenter, og som angivet ovenfor, bruger det første argument som separator.

Hvordan behandler concat_ws() NULL?

postgres=> SELECT concat_ws('-',333,NULL,1919) AS cell_num;
cell_num
----------
333-1919
(1 row)
postgres=> SELECT concat_ws(NULL,333,454,1919) AS cell_num;
cell_num
----------
(1 row)

NULL ignoreres, medmindre det er separatorargumentet givet til concat_ws().

Derefter ignoreres alle argumenter, og NULL returneres i stedet.

Sammenkædning er cool...

Nu hvor vi har en idé om, hvordan sammenkædning fungerer, lad os se på et par eksempler på det.

Tilbage til den mock-dvd-lejedatabase

Antag, at vi skal udarbejde en liste over kunders for- og efternavne sammen med deres e-mailadresse for at sende et notat til opdatering af deres konto.

Jeg vil begrænse output til kun 10 rækker for korthedens skyld, men stadig demonstrere || operatør.

dvdrental=> SELECT first_name||' '||last_name||'''s email address is: '||email AS name_and_email
FROM customer
LIMIT 10;
name_and_email
--------------------------------------------------------------------------
Jared Ely's email address is: [email protected]
Mary Smith's email address is: [email protected]
Patricia Johnson's email address is: [email protected]
Linda Williams's email address is: [email protected]
Barbara Jones's email address is: [email protected]
Elizabeth Brown's email address is: [email protected]
Jennifer Davis's email address is: [email protected]
Maria Miller's email address is: [email protected]
Susan Wilson's email address is: [email protected]
Margaret Moore's email address is: [email protected]
(10 rows)

Bemærk, at vi var nødt til at undslippe det enkelte citat, der blev brugt med apostrof s, ved at bruge et ekstra enkelt citat for at vise besiddelse af e-mailadressen for hver kunde.

Hvorfor skulle du vide det?

Der kan være tidspunkter, hvor sammenkædning af data giver dig bedre indsigt og forståelse for det datasæt, du arbejder med. Sammen med rapporteringsmuligheder kan sammenkædning af delte datasæt med andres potentielt gøre dem (dataene) mere læsbare og fordøjelige.

3. Leverer IN-værdiliste med underforespørgsler

En underforespørgsel har adskillige kraftfulde anvendelser. Af disse er det almindeligt at angive en IN-liste med værdier, der skal kontrolleres for medlemskab.

Her er en hurtig brug.

Antag, at vi har kunde- og betalingstabeller i en falsk dvd-udlejningsbutik og ønsker at belønne vores top fem mest forbrugende kunder, som lejede film i dagene 10. - 13. april.

Forestil dig, at det er en særlig målperiode. Så hvis kunden brugte mere end 30 USD, vil vi gerne anerkende dem.

Husk på, at der er andre tilgængelige muligheder for at løse denne type spørgsmål (dvs. joinforbindelser, indfangning af resultater fra flere valg osv...), men underforespørgsler kan også håndtere det.

Vi starter ud med hele shebang her. Denne komplette forespørgsel returnerer alt, hvad vi ønsker for dette specifikke spørgsmål.

dvdrental=> SELECT first_name, last_name, email
FROM customer
WHERE customer_id IN (
SELECT customer_id FROM (
SELECT DISTINCT customer_id, SUM(amount)
FROM payment
WHERE extract(month from payment_date) = 4
AND extract(day from payment_date) BETWEEN 10 AND 13
GROUP BY customer_id
HAVING SUM(amount) > 30
ORDER BY SUM(amount) DESC
LIMIT 5) AS top_five);

Dette eksempel indeholder faktisk indlejrede underforespørgsler, hvoraf den ene er en afledt tabel.

Lad os starte med at bore ind i den inderste underforespørgsel, den afledte tabel.

Denne underforespørgsel er en selvstændig SELECT-sætning, der returnerer et kunde_id og en SUM() i beløbskolonnen.

Kun de kunder, der opfylder de kriterier, der er kontrolleret af WHERE- og HAVING-klausulerne, foretager snittet og bliver yderligere tyndet ud med LIMIT 5;

Hvorfor den næste underforespørgsel, du spørger?

Kan vi ikke bare bruge WHERE customer_id IN-delen af ​​den yderste SELECT her?

Lad os se med en praktisk tilgang.

Jeg vil fjerne AS top_five fra underforespørgslen og prøve den yderste forespørgsel med den nu:

dvdrental=> SELECT first_name, last_name, email
FROM customer
WHERE customer_id IN
(SELECT DISTINCT customer_id, SUM(amount)
FROM payment
WHERE extract(month from payment_date) = 4
AND extract(day from payment_date) BETWEEN 10 AND 13
GROUP BY customer_id
HAVING SUM(amount) > 30
ORDER BY SUM(amount) DESC
LIMIT 5);
ERROR: subquery has too many columns
LINE 3: WHERE customer_id IN (

Her testes IN-medlemskab kun med kolonnen customer_id, alligevel returnerer den afledte tabel to kolonner, og PostgreSQL giver os besked.

Et middel er at bruge en anden underforespørgsel. Hvis du kun vælger customer_id fra sæt af afledte tabelresultater, oprettes den næste indre indlejrede underforespørgsel.

Nu indeholder IN-prædikatet flere rækker af én kolonnes værdier for at kontrollere medlemskab i forhold til WHERE-sætningen for customer_id for at gøre de endelige resultater indstillet.

Hvorfor betyder det noget?

Det er effektivt at bruge underforespørgsler på denne måde på grund af antallet af værdier, der potentielt kan testes med IN()-prædikatet.

Tænk hvis der var 100? Eller mere?

'Hårdkodning ' alle på IN()-listen kan blive problematiske og fejltilbøjelige, efterhånden som mængden af ​​værdier stiger.

4. gener_series()

Dette sæt returfunktion er praktisk og super sjovt at bruge og udforske. Jeg har brugt gener_series() i ovenstående eksempler, men det fortjener en snak for sig selv. Fokuserer mere på funktionen og mulighederne.

Jeg finder gener_series() nyttig til sammenlignende forespørgsler, hvor nogle eller alle data mangler.

Eller kun delvise data er tilgængelige på det tidspunkt, jeg udforsker. En praktisk brug er at udfylde tabeller med 'dummy-data '.

Til at starte med vil vi oprette en simpel tabel:

trial=> CREATE TABLE tbl_1(
trial(> tb_id SERIAL PRIMARY KEY,
trial(> some_day DATE,
trial(> an_amt NUMERIC(4,2));
CREATE TABLE

Brug derefter gener_series() som VÆRDIER for vores INSERT-sætning:

trial=> INSERT INTO tbl_1(some_day, an_amt)
VALUES(
generate_series('2018-04-01','2018-04-15',INTERVAL '1 day'),
generate_series(2.43, 34.20, 1.03));
INSERT 0 31

Opret derefter en anden tabel

trial=> CREATE TABLE tbl_2(
tb2_id SERIAL PRIMARY KEY,
some_day2 DATE,
an_amt2 NUMERIC(4,2));
CREATE TABLE

Udfyld det også ved at bruge gener_series() i INSERT-sætningen:

trial=> INSERT INTO tbl_2(some_day2, an_amt2)
VALUES(
generate_series('2018-05-16','2018-05-31',INTERVAL '1 day'),
generate_series(15.43, 31., 1.03));
INSERT 0 16

Hvorfor betyder det noget?

For at gentage, gener_series() er så nyttigt til at skabe falske eller øve data.

Jeg har fundet ud af, at efterligning af måneds- eller dagintervaller til sammenligning er enestående med gener_series(). Se afsnit 1 og CTE der viser denne brug.

At oprette et sæt komplette data med gener_series() og bruge til at sammenligne med lagrede data for at afgøre, om der mangler data, har også stor værdi.

5. Forespørgslen er med COUNT() Aggregeringsfunktionen.

Denne enkle, men effektive samlede funktion burde være i enhvers arsenal. Især når man udforsker tabeller eller datasæt for første gang.

Jeg mener, vil du virkelig 'vælge alt ' fra en tabel med 1 mio. rækker?

Bestem med COUNT(*) hvor mange poster der er til stede, før du indlæser.

Lad os finde ud af, hvor mange rækker filmbordet har i denne falske DVD-lejetabel:

dvdrental=> SELECT COUNT(*)
dvdrental-> FROM film;
count
-------
1000
(1 row)

Selvom det ikke er helt så omfattende som 1M+ rækker, er jeg sikker på, at du kan se nytten.

For at returnere antallet af specifikke rækker kan COUNT(*) filtreres med en WHERE-sætning.

Lad os se, hvor mange film der har en "G"-vurdering:

dvdrental=> SELECT COUNT(*)
dvdrental-> FROM film
dvdrental-> WHERE rating = 'G';
count
-------
178
(1 row)

Der er en anden form for COUNT() at være opmærksom på. COUNT(noget_udtryk) .

Forskellene mellem dem er:

  • COUNT(*) returnerer summen af ​​alle inputrækker (inklusive NULLS og dubletter).
  • COUNT(noget_udtryk ) tæller antallet af ikke-NULL-input rækker.

Når det bruges sammen med nøgleordet DISTINCT, vil COUNT() eliminere duplikerede indtastninger og kun returnere unikke værdier.

Lad os se det i aktion ved at bruge COUNT() med DISTINCT for at bestemme, hvor mange unikke typer vurderinger, der er til stede:

dvdrental=> SELECT COUNT(DISTINCT rating) FROM film;
count
-------
5
(1 row)

Med denne forespørgsel ved vi, at der er 5 typer vurderinger.

Hvorfor betyder det noget?

Afhængigt af, hvad der bliver sporet eller målrettet, kan det være vigtigt at vide, hvor mange af noget der findes. Brug derfor COUNT(*) eller COUNT(noget_udtryk ) hjælper med disse typer udfordringer.

Bare husk at COUNT(*) ikke ignorerer NULL. Alle rækker, duplikat- og NULL-værdier inkluderet, returneres som en del af det endelige tal.

6. OPDATERE flere rækker med et CASE-udtryk.

Antag, at vi har denne tabel:

trial=> SELECT * FROM reward_members;
rm_id | expense_amt | member_status
-------+-------------+---------------
1 | 1245.33 | gold
2 | 1300.49 | gold
3 | 900.20 | bronze
4 | 2534.44 | platinum
5 | 600.19 | bronze
6 | 1001.55 | silver
7 | 1097.99 | silver
8 | 3033.33 | platinum
(8 rows)

Vi skal omdøbe medlemsstatus-kolonnen og tilføje 'gruppe ' til slutningen af ​​det aktuelle navn for hver post.

Til at begynde med vil flere individuelle UPDATE-sætninger gøre dette uden problemer.

Men det kan et enkelt CASE-udtryk også.

trial=> UPDATE reward_members
SET member_status = (
CASE member_status
WHEN 'gold' THEN 'gold_group'
WHEN 'bronze' THEN 'bronze_group'
WHEN 'platinum' THEN 'platinum_group'
WHEN 'silver' THEN 'silver_group'
END
)
WHERE member_status IN ('gold', 'bronze','platinum', 'silver');
UPDATE 8

Lad os forespørge i tabellen igen for at se ændringerne:

trial=> SELECT * FROM reward_members;
rm_id | expense_amt | member_status
-------+-------------+----------------
1 | 1245.33 | gold_group
2 | 1300.49 | gold_group
3 | 900.20 | bronze_group
4 | 2534.44 | platinum_group
5 | 600.19 | bronze_group
6 | 1001.55 | silver_group
7 | 1097.99 | silver_group
8 | 3033.33 | platinum_group
(8 rows)

Alle opdateringer lykkedes.

Hvorfor betyder det noget?

Du kan forestille dig, hvor mange rundrejser dette ville tage til serveren, hvis flere individuelle UPDATE-sætninger var blevet kørt. I sandhed kun 4 for dette eksempel. Men alligevel er potentialet for mange der altid.

Men ved at bruge en OPDATERING med CASE-udtryk sender vi kun én forespørgsel i stedet for.

7. COPY og \copy

PostgreSQL leverer COPY, en kommando til eksport af data mellem filer og tabeller.

Vær sikker på og besøg det medfølgende link for at se det rigelige antal muligheder, der er tilgængelige med COPY.

En vigtig bemærkning om COPY. SUPERUSER rolleprivilegium er påkrævet for at udføre denne kommando.

psql-metakommandoen \copy er et alternativ for de brugere, der ikke anses for denne rolleattribut. Vi besøger den kommando igen snart.

Lad os først køre en COPY-kommando for at eksportere bestemte kolonner til en CSV-fil på den lokale maskine.

Antag, at vi har dette forespørgselsresultat til eksport:

trial=# SELECT expense_amt, member_status
trial-# FROM reward_members
trial-# WHERE member_status = 'gold_group';
expense_amt | member_status
-------------+---------------
1245.33 | gold_group
1300.49 | gold_group
(2 rows)

Med COPY kan vi bruge den SELECT-sætning til at fuldføre denne eksport.

trial=# COPY (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'gold_group')
TO '/home/linux_user_here/awards_to_honor.csv'
DELIMITER ','
CSV HEADER;
COPY 2

*Bemærk:Ifølge dokumentationen skal forespørgslen være inden for parentes.

Lad os nu tjekke indholdet af den fil:

$ cat awards_to_honor.csv
expense_amt,member_status
1245.33,gold_group
1300.49,gold_group

Vi kan se, at den første linje indeholder HEADER (som er kolonnenavnene), og begge linjer har data for cost_amt og member_status for begge kolonner, der returneres fra WHERE-sætningsfilteret.

En anden vigtig advarsel opdagede jeg ved at udføre ovenstående COPY-kommando.

Brugeren skal have privilegier for at skrive til filen på OS-niveau.

I mit tilfælde rettet med:

$ sudo chown postgres awards_to_honor.csv

Du kan undgå dette problem ved i stedet at skrive til en systemfil, som den aktuelle bruger har adgang til, såsom /tmp (vist nedenfor.)

trial=# COPY (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'gold_group')
TO '/tmp/awards_to_honor.csv'
DELIMITER ','
CSV HEADER;
COPY 2

Men en af ​​mine testroller uden SUPERUSER-attributten løb ind i problemer med at skrive til /tmp-filen.

Se nedenfor for bekræftelse:

trial=# SET role log_user; -- changing from postgres user to log_user
SET

Prøv nu den samme COPY-kommando, og skriv til /tmp-mappen

trial=> COPY (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'gold_group')
TO '/tmp/awards_to_honor2.csv'
DELIMITER ','
CSV HEADER;
ERROR: must be superuser to COPY to or from a file
HINT: Anyone can COPY to stdout or from stdin. psql's \copy command also works for anyone.

Måske en bedre målestok, som foreslået i TIP:, for roller uden SUPERUSER-attributten, er psql \copy meta-kommandoen.

Lad os udføre en lignende type kommando med \copy i stedet for at bruge den samme rolle, uden behov for den SUPERUSER-attribut.

trial=> \copy (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'silver_group')
TO '/home/linux_user_here/more_awards.csv'
DELIMITER ','
CSV HEADER;
COPY 2

Ingen problemer der.

Og filernes indhold,

$ cat more_awards.csv
expense_amt,member_status
1001.55,silver_group
1097.99,silver_group

Virker også for /tmp-mappen:

trial=> \copy (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'silver_group')
TO '/tmp/more_awards.csv'
DELIMITER ','
CSV HEADER;
COPY 2

Samme indhold findes også i den skrevne fil:

trial=> \! cat /tmp/more_awards.csv
expense_amt,member_status
1001.55,silver_group
1097.99,silver_group

Hvorfor betyder det noget?

Import af data til PostgreSQL via filer er en sikker masseoverførselsmetode. Selvom alle ikke er dækket i dette blogindlæg, tilbyder COPY og \copy begge flere muligheder for at arbejde med forskellige filformater og filtypenavne.

På samme måde håndteres eksport af data fra tabeller eller specifikke kolonner også nemt med begge disse kommandoer.

8. psql \help meta-kommando

Du er i en psql kommandolinjesession. Er du nysgerrig efter CREATE INDEX kommandosyntaksen?

Intet behov og gå til en browser eller et andet dokument.

Prøv dette i stedet:

trial=> \help CREATE INDEX
Command: CREATE INDEX
Description: define a new index
Syntax:
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON table_name [ USING method ]
( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )
[ WITH ( storage_parameter = value [, ... ] ) ]
[ TABLESPACE tablespace_name ]
[ WHERE predicate ]

For at vide, hvilken hjælpetekst der er tilgængelig, kan du køre \help alene og få en liste over tilgængelige muligheder.

Jeg vil ikke liste dem alle herude, bare ved, at den mulighed er tilgængelig.

Hvorfor betyder det noget?

Den kendsgerning, at denne metakommando er super nem at bruge, kraftfuld og bekvem, er nok fordele til at nævne det her. Det har sparet mig for masser af tid brugt på at søge i anden dokumentation. Og som nybegynder bruger jeg det selvfølgelig ret ofte!

Konklusion

Dette er ikke en udtømmende liste. Heller ikke 'be all end all ' af forespørgsler og datamanipulation.

Kun mit bud på dem, der vækker min interesse og taler til mig, mens jeg fortsætter med at lære og vokse til en SQL-udviklerrolle. Jeg håber, at du gennem dette blogindlæg vil finde use cases for ovenstående forespørgsler og kommandoer, og implementere dem, hvor du finder passende.


  1. Kald til udefineret funktion oci_connect, php_oci8_12c.dll, windows 8.1, php5.6.6

  2. Sådan fungerer LEFT() i MariaDB

  3. PostgreSQL IF-erklæring

  4. DBaaS, cloud og transparent forespørgselsrouting