PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Mes requêtes PostgreSQL préférées et pourquoi elles sont importantes

Les bases de données, les tables, la normalisation et un plan de sauvegarde solide nous permettent de stocker et de maintenir les données.

Ces meilleures pratiques combinées, à leur tour, nous permettent d'interagir avec ces données. Dans le monde actuel axé sur les données, les données sont précieuses. Non seulement précieuses, les données sont souvent essentielles pour les solutions d'utilisateur final fournies par les produits et services. L'extraction d'informations, la réponse à des questions et des métriques significatives à partir de données au moyen d'interrogations et de manipulations de données font partie intégrante de SQL en général.

PostgreSQL n'est pas différent.

Ce nœud fondamental est essentiel au succès de tout aspect axé sur les données.

Ci-dessous, je présente une combinaison de 8 requêtes ou types de requêtes différents que j'ai trouvés intéressants et attrayants pour explorer, étudier, apprendre ou manipuler des ensembles de données.

Ils ne sont répertoriés dans aucun ordre d'importance.

La plupart seront probablement de vieux amis familiers. Peut-être que certains deviendront de nouvelles connaissances.

Les exemples de tables et de données utilisées ne sont pas aussi importants que la construction réelle des requêtes elles-mêmes et ce que chaque requête renvoie, offre ou fournit. Beaucoup d'entre eux sont fictifs et dérivés à des fins de démonstration et ne doivent pas être pris au pied de la lettre dans leurs valeurs.

1. Jointure à gauche, attention aux valeurs nulles à droite...

Supposons que dans cet exemple, nous ayons une vente en cours de deux mois et que nous obtenions un total des deux combinés.

Pourtant, pour une raison quelconque, le deuxième mois n'a pas pesé et nous voulons cibler les jours du premier mois qui ont pris le relais.

Ces ventes sont représentées sous forme de tables payment et fake_month pour cette démonstration.

A noter :

  • Nous ne vérifierons que les totaux supérieurs à 2 000.
  • Nous allons limiter la sortie à seulement 10 lignes.

Pour commencer, nous avons cette Common Table Expression (CTE) 'générant ' la table fake_month pour nous, et la requête qui suit.

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)

On dirait que les deux mois y ont contribué. Alors est-ce résolu ?

Avant de considérer cela résolu, visitons la clause ORDER BY.

Bien sûr, vous pouvez COMMANDER PAR ASC ou DESC.

Cependant, vous pouvez également ORDER BY NULLS en premier ou en dernier et cela change un peu les choses.

Réécrivons cette requête et utilisons d'abord ORDER BY NULLS sur la colonne légitime.

Par souci de concision, je vais supprimer le CTE de la sortie, sachez simplement qu'il est toujours là et qu'il est utilisé.

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)

Il n'y a aucune différence.

Que se passe-t-il si nous ORDER BY NULLS d'abord sur la fausse colonne ? Celui de droite côté du JOIN ?

Voyons.

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)

Maintenant, nous arrivons quelque part. Nous pouvons voir pour les jours 29 et 30, la fausse colonne a été commandée à partir du haut de l'ensemble de résultats.

En raison de ORDER BY faux NULLS en premier.

Cela résout notre question, à quels jours la "vente 2" s'est-elle relâchée.

Vous vous demandez...

"Pouvons-nous simplement filtrer avec WHERE fake IS NULL ? "

Comme ceci :

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)

Oui ça marche. Alors pourquoi ne pas simplement utiliser cette requête à la place ? Pourquoi c'est important ?

Je pense que l'utilisation de LEFT JOIN et ORDER BY NULLS en premier pour la table sur le côté droit de JOIN est un excellent moyen d'explorer des tables et des ensembles de données inconnus.

En confirmant, le cas échéant, quelles données sont "manquantes ' de ce côté de la condition de jointure en premier ; améliore la clarté et la sensibilisation, vous permettant ensuite de filtrer les résultats définis avec la clause WHERE IS NULL, finalisant les choses.

Bien sûr, la familiarité avec les tables et les ensembles de données pourrait potentiellement éliminer le besoin de LEFT JOIN présenté ici.

C'est une requête valable pour toute personne utilisant PostgreSQL d'essayer au moins, pendant l'exploration.

2. Concaténation de chaînes

La concaténation, la jonction ou l'ajout de deux chaînes, fournit une option de présentation pour les ensembles de résultats. Beaucoup de 'choses ' peut être concaténé.

Cependant, comme indiqué dans la documentation, l'opérateur de concaténation de chaînes ('||') accepte les entrées non-chaîne, tant qu'il s'agit d'une chaîne.

Voyons quelques exemples avec les requêtes ci-dessous :

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

Nous pouvons voir que les nombres et les chaînes peuvent tous être concaténés comme mentionné ci-dessus.

Le '||' n'est que l'un de ceux disponibles dans PostgreSQL.

La fonction concat() accepte plusieurs arguments, les concaténant tous au retour.

Voici un exemple de cette fonction en action :

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

Nous pouvons passer plus de deux arguments si vous le souhaitez :

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

Notons quelque chose de très rapide avec ces exemples suivants :

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)

Notez que la fonction concat() ignore NULL, quel que soit son emplacement dans la liste des paramètres, contrairement à l'opérateur de concaténation de chaînes.

NULL est renvoyé s'il est présent n'importe où dans la chaîne à concaténer.

Soyez juste conscient de cela.

Au lieu d'inclure manuellement dans la chaîne à concaténer, PostgreSQL inclut également une fonction concat_ws() qui accepte un séparateur de chaîne comme premier paramètre.

Nous allons le visiter avec ces requêtes :

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() accepte des nombres ou des chaînes comme arguments et, comme indiqué ci-dessus, utilise le premier argument comme séparateur.

Comment concat_ws() traite-t-il 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 est ignoré sauf s'il s'agit de l'argument séparateur donné à concat_ws().

Ensuite, tous les arguments sont ignorés et NULL est renvoyé à la place.

La concaténation c'est cool...

Maintenant que nous avons une idée du fonctionnement de la concaténation, examinons quelques exemples.

Retour à la base de données de location de faux DVD

Supposons que nous ayons besoin de compiler une liste de noms et prénoms de clients, ainsi que leur adresse e-mail pour envoyer un mémo de mise à jour de leur compte.

Je limiterai la sortie à seulement 10 lignes par souci de brièveté, mais en démontrant toujours le || opérateur.

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)

Notez que nous avons dû échapper au guillemet simple utilisé avec les apostrophes, en utilisant un guillemet simple supplémentaire pour montrer la possession de l'adresse e-mail de chaque client.

Pourquoi devriez-vous savoir ?

Il peut arriver que la concaténation des données vous offre une meilleure compréhension et une meilleure compréhension de l'ensemble de données avec lequel vous travaillez. Outre les options de création de rapports, la concaténation des ensembles de données partagés avec d'autres pourrait potentiellement les rendre (les données) plus lisibles et digestes.

3. Fournir une liste de valeurs IN avec des sous-requêtes

Une sous-requête a de nombreuses utilisations puissantes. Parmi ceux-ci, il est courant de fournir une liste IN de valeurs pour vérifier l'appartenance.

Voici une utilisation rapide.

Supposons que nous ayons des tables de clients et de paiements dans un faux magasin de location de DVD et que nous voulions récompenser nos cinq clients les plus dépensiers qui ont loué des films du 10 au 13 avril.

Imaginez que c'est une période cible spéciale. Donc, si le client a dépensé plus de 30 $, nous voulons le remercier.

Gardez à l'esprit qu'il existe d'autres options disponibles pour résoudre ce type de question (par exemple, les jointures, la capture des résultats de plusieurs sélections, etc.), mais les sous-requêtes peuvent également le gérer.

Nous allons commencer par tout le tralala ici. Cette requête complète renvoie tout ce que nous voulons pour cette question particulière.

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);

Cet exemple contient en fait des sous-requêtes imbriquées, dont l'une est une table dérivée.

Commençons par explorer la sous-requête la plus profonde, cette table dérivée.

Cette sous-requête est une instruction SELECT autonome qui lui est propre, renvoyant un customer_id et un SUM() sur la colonne du montant.

Seuls les clients répondant aux critères vérifiés par les clauses WHERE et HAVING font la coupe, étant encore amincis avec LIMIT 5 ;

Pourquoi la prochaine sous-requête que vous posez ?

Ne pouvons-nous pas simplement utiliser la partie WHERE customer_id IN du SELECT le plus externe ici ?

Voyons avec une approche pratique.

Je vais supprimer l'AS top_five de la sous-requête et essayer la requête la plus externe avec maintenant :

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 (

Ici, l'appartenance IN est testée avec uniquement la colonne customer_id, mais la table dérivée renvoie deux colonnes et PostgreSQL nous le fait savoir.

Un remède consiste à utiliser une autre sous-requête. La sélection uniquement de customer_id dans l'ensemble de résultats de la table dérivée crée la prochaine sous-requête interne imbriquée.

Désormais, le prédicat IN contient plusieurs lignes des valeurs d'une colonne pour vérifier l'appartenance à la clause WHERE pour customer_id afin de définir les résultats finaux.

Pourquoi c'est important ?

L'utilisation des sous-requêtes de cette manière est puissante en raison du nombre de valeurs qui pourraient potentiellement être testées avec le prédicat IN().

Imaginez s'il y avait un 100? Ou plus ?

'Codage en dur ' tous dans la liste IN() pourraient devenir problématiques et sujets aux erreurs à mesure que le volume de valeurs augmente.

4. generate_series()

Cette fonction de retour d'ensemble est pratique et super amusante à utiliser et à explorer. J'ai utilisé generate_series() dans les exemples ci-dessus, mais cela mérite une discussion en soi. Se concentrer davantage sur la fonction et les capacités.

Je trouve generate_series() utile pour les requêtes comparatives où certaines ou toutes les données sont manquantes.

Ou seules des données partielles sont disponibles au moment où j'explore. Une utilisation pratique consiste à remplir des tables avec des 'données factices '.

Pour commencer, nous allons créer un tableau simple :

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

Utilisez ensuite generate_series() comme VALUES pour notre instruction INSERT :

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

Créez ensuite une seconde table

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

Remplissez-le également à l'aide de generate_series() dans l'instruction INSERT :

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

Pourquoi c'est important ?

Pour réitérer, generate_series() est très utile pour créer des données fictives ou d'entraînement.

J'ai trouvé que l'imitation des plages de mois ou de jours à des fins de comparaison est exceptionnelle avec generate_series(). Reportez-vous à la section 1 et le CTE y démontre cette utilisation.

Créer un ensemble de données complet avec generate_series() et l'utiliser pour comparer les données stockées afin de déterminer si des données manquent a également une grande valeur.

5. Requête avec la fonction d'agrégation COUNT() .

Cette fonction d'agrégat simple mais efficace devrait être dans l'arsenal de n'importe qui. Surtout lors de l'exploration de tables ou d'ensembles de données pour la première fois.

Je veux dire, voulez-vous vraiment 'tout sélectionner ' à partir d'une table avec 1 million de lignes ?

Déterminez avec COUNT(*) le nombre d'enregistrements présents avant de charger.

Découvrons combien de rangées la table de film a dans cette simulation de table de location de DVD :

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

Bien qu'il ne soit pas aussi étendu que plus de 1 million de lignes, je suis sûr que vous en voyez l'utilité.

Pour renvoyer le nombre de lignes spécifiques, COUNT(*) peut être filtré avec une clause WHERE.

Voyons combien de films sont notés "G" :

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

Il existe une autre forme de COUNT() à connaître. COUNT(some_expression) .

Les différences entre eux sont :

  • COUNT(*) renvoie le total de toutes les lignes d'entrée (y compris les valeurs NULL et les doublons).
  • COUNT(une_expression ) compte le nombre de lignes d'entrée non NULL.

Lorsqu'il est utilisé conjointement avec le mot-clé DISTINCT, COUNT() éliminera les entrées en double et ne renverra que des valeurs uniques.

Voyons cela en action en utilisant COUNT() avec DISTINCT pour déterminer combien de types uniques de notes sont présents :

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

Avec cette requête, nous savons qu'il existe 5 types d'évaluations.

Pourquoi c'est important ?

Selon ce qui est suivi ou ciblé, savoir combien de quelque chose existe peut être important. Par conséquent, en utilisant COUNT(*) ou COUNT(some_expression ) aide à relever ces types de défis.

N'oubliez pas que COUNT(*) n'ignore pas NULL. Toutes les lignes, valeurs en double et NULL incluses, sont renvoyées dans le cadre du nombre final.

6. UPDATE plusieurs lignes avec une expression CASE.

Supposons que nous ayons ce tableau :

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)

Nous devons renommer la colonne member_status et ajouter 'group ' à la fin du nom actuel présent pour chaque enregistrement.

Pour commencer, plusieurs instructions UPDATE individuelles permettront d'accomplir cela sans problème.

Mais une seule expression CASE le peut aussi.

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

Interrogeons à nouveau la table pour voir les changements :

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)

Toutes les mises à jour ont réussi.

Pourquoi c'est important ?

Vous pouvez imaginer combien d'allers-retours cela prendrait au serveur si plusieurs instructions UPDATE individuelles avaient été exécutées. En vérité, seulement 4 pour cet exemple. Néanmoins, le potentiel pour beaucoup est toujours là.

Pourtant, en utilisant une expression UPDATE avec CASE, nous n'envoyons qu'une seule requête à la place.

7. COPIER et \copier

PostgreSQL fournit COPY, une commande pour exporter des données entre fichiers et tables.

Assurez-vous de visiter le lien fourni pour voir le nombre abondant d'options disponibles avec COPY.

Une remarque importante concernant COPY. Le privilège de rôle SUPERUSER est requis pour exécuter cette commande.

La méta-commande psql \copy est une alternative pour les utilisateurs qui ne sont pas considérés comme cet attribut de rôle. Nous visiterons cette commande à tour de rôle.

Exécutons d'abord une commande COPY pour exporter certaines colonnes vers un fichier CSV sur la machine locale.

Supposons que nous ayons ce résultat de requête à exporter :

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)

Avec COPY, nous pouvons utiliser cette instruction SELECT pour terminer cette exportation.

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

*Remarque :selon la documentation, la requête doit être entre parenthèses.

Vérifions maintenant le contenu de ce fichier :

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

Nous pouvons voir que la première ligne contient le HEADER (qui sont les noms de colonne) et les deux lignes ont les données dépense_amt et member_status pour les deux colonnes renvoyées par le filtre de clause WHERE.

Une autre mise en garde importante que j'ai découverte en exécutant la commande COPY ci-dessus.

L'utilisateur doit disposer de privilèges pour écrire dans le fichier au niveau du système d'exploitation.

Dans mon cas, corrigé avec :

$ sudo chown postgres awards_to_honor.csv

Vous pouvez éviter ce problème en écrivant à la place dans un fichier système auquel l'utilisateur actuel a accès, tel que /tmp (illustré ci-dessous).

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

Cependant, l'un de mes rôles de test sans l'attribut SUPERUSER a rencontré des problèmes d'écriture dans le fichier /tmp.

Voir ci-dessous pour confirmation :

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

Essayez maintenant la même commande COPY, en écrivant dans le dossier /tmp

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.

Peut-être une meilleure mesure, comme suggéré dans le CONSEIL :, pour les rôles sans l'attribut SUPERUSER, est la méta-commande psql \copy.

Exécutons un type de commande similaire avec \copy à la place en utilisant le même rôle, sans avoir besoin de cet attribut SUPERUSER.

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

Aucun problème.

Et le contenu des fichiers,

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

Fonctionne également pour le dossier /tmp :

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

Même contenu présent dans le fichier écrit également :

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

Pourquoi c'est important ?

L'importation de données dans PostgreSQL via des fichiers est une méthode de téléchargement en masse infaillible. Bien que tous ne soient pas couverts dans cet article de blog, COPY et \copy les deux offrent plusieurs options pour travailler avec différents formats de fichiers et extensions.

De la même manière, l'exportation de données à partir de tables ou de colonnes spécifiques est également facilement gérée avec ces deux commandes.

8. psql \help méta-commande

Vous êtes dans une session de ligne de commande psql. Vous êtes curieux de connaître la syntaxe de la commande CREATE INDEX ?

Pas besoin d'aller dans un navigateur ou un autre document.

Essayez ceci à la place :

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 ]

Pour savoir quel texte d'aide est disponible, vous pouvez exécuter \help seul et obtenir une liste des options disponibles.

Je ne vais pas tous les énumérer ici, sachez simplement que cette option est disponible.

Pourquoi c'est important ?

Le fait que cette méta-commande soit super facile à utiliser, puissante et pratique suffit à le mentionner ici. Cela m'a épargné des tonnes de temps passé à chercher dans d'autres documents. Et bien sûr, étant novice, je l'utilise assez souvent !

Conclusion

Ce n'est pas une liste exhaustive. Ni le 'be all end all ' des requêtes et de la manipulation des données.

Seul mon point de vue sur ceux qui piquent mon intérêt et me parlent alors que je continue à apprendre et à évoluer dans un rôle de développeur SQL. J'espère qu'à travers cet article de blog, vous trouverez des cas d'utilisation pour les requêtes et commandes ci-dessus, en implémentant celles qui vous conviennent.