Installez le module supplémentaire tablefunc
une fois par base de données, qui fournit la fonction crosstab()
. Depuis Postgres 9.1, vous pouvez utiliser CREATE EXTENSION
pour cela :
CREATE EXTENSION IF NOT EXISTS tablefunc;
Cas de test amélioré
CREATE TABLE tbl (
section text
, status text
, ct integer -- "count" is a reserved word in standard SQL
);
INSERT INTO tbl VALUES
('A', 'Active', 1), ('A', 'Inactive', 2)
, ('B', 'Active', 4), ('B', 'Inactive', 5)
, ('C', 'Inactive', 7); -- ('C', 'Active') is missing
Formulaire simple - ne convient pas aux attributs manquants
crosstab(text)
avec 1 paramètre d'entrée :
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- needs to be "ORDER BY 1,2" here
) AS ct ("Section" text, "Active" int, "Inactive" int);
Renvoie :
SectionSection | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | 7 | -- !!
- Pas besoin de caster et de renommer.
- Notez le incorrect résultat pour
C
:la valeur7
est rempli pour la première colonne. Parfois, ce comportement est souhaitable, mais pas pour ce cas d'utilisation. - Le formulaire simple est également limité à exactement trois colonnes dans la requête d'entrée fournie :row_name , catégorie , valeur . Il n'y a pas de place pour les colonnes supplémentaires comme dans l'alternative à 2 paramètres ci-dessous.
Formulaire sécurisé
crosstab(text, text)
avec 2 paramètres d'entrée :
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- could also just be "ORDER BY 1" here
, $$VALUES ('Active'::text), ('Inactive')$$
) AS ct ("Section" text, "Active" int, "Inactive" int);
Renvoie :
SectionSection | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | | 7 -- !!
-
Notez le résultat correct pour
C
. -
Le deuxième paramètre peut être n'importe quelle requête renvoyant une ligne par attribut correspondant à l'ordre de la définition de colonne à la fin. Souvent, vous souhaiterez interroger des attributs distincts de la table sous-jacente comme ceci :
'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
C'est dans le manuel.
Étant donné que vous devez de toute façon épeler toutes les colonnes dans une liste de définition de colonne (sauf pour crosstabN()
variantes), il est généralement plus efficace de fournir une courte liste dans un VALUES
expression comme démontré :
$$VALUES ('Active'::text), ('Inactive')$$)
Ou (pas dans le manuel) :
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
-
J'ai utilisé des cotations en dollars pour faciliter la citation.
-
Vous pouvez même sortir des colonnes avec différentes types de données avec
crosstab(text, text)
- tant que la représentation textuelle de la colonne de valeur est une entrée valide pour le type cible. De cette façon, vous pourriez avoir des attributs de différents types et affichertext
,date
,numeric
etc. pour les attributs respectifs. Il y a un exemple de code à la fin du chapitrecrosstab(text, text)
dans le manuel.
db<>jouez ici
Effet des lignes d'entrée excessives
Les lignes d'entrée excédentaires sont gérées différemment - lignes en double pour la même combinaison ("row_name", "category") - (section, status)
dans l'exemple ci-dessus.
Le 1-paramètre Le formulaire remplit les colonnes de valeurs disponibles de gauche à droite. Les valeurs excédentaires sont ignorées.
Les premières lignes d'entrée prévalent.
Le 2 paramètres Le formulaire affecte chaque valeur d'entrée à sa colonne dédiée, écrasant toute affectation précédente.
Les lignes d'entrée ultérieures prévalent.
En règle générale, vous n'avez pas de doublons pour commencer. Mais si vous le faites, ajustez soigneusement l'ordre de tri à vos besoins - et documentez ce qui se passe.
Ou obtenez rapidement des résultats arbitraires si vous ne vous en souciez pas. Soyez juste conscient de l'effet.
Exemples avancés
-
Pivot sur plusieurs colonnes à l'aide de Tablefunc - démontrant également les "colonnes supplémentaires" mentionnées
-
Alternative dynamique au pivot avec CASE et GROUP BY
\crosstabview
en psql
Postgres 9.6 a ajouté cette méta-commande à son terminal interactif par défaut psql. Vous pouvez exécuter la requête que vous utiliseriez comme premier crosstab()
paramètre et alimentez-le dans \crosstabview
(immédiatement ou à l'étape suivante). Comme :
db=> SELECT section, status, ct FROM tbl \crosstabview
Résultat similaire à celui ci-dessus, mais il s'agit d'une fonctionnalité de représentation côté client exclusivement. Les lignes d'entrée sont traitées légèrement différemment, d'où ORDER BY
n'est pas requis. Détails pour \crosstabview
dans le manuel. Il y a plus d'exemples de code au bas de cette page.
Réponse connexe sur dba.SE par Daniel Vérité (l'auteur de la fonctionnalité psql) :
- Comment puis-je générer un CROSS JOIN pivoté où la définition de table résultante est inconnue ?