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);
Retour:
Section | Actif | Inactif
--------- + -------- + ----------
A | 1 | 2
B | 4 | 5
C | 7 | - !!
- Pas besoin de couler et de renommer.
- Notez le résultat incorrect pour
C
: la valeur 7
est remplie 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 , category , value . Il n'y a pas de place pour des colonnes supplémentaires comme dans l'alternative à 2 paramètres ci-dessous.
Forme sûre
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);
Retour:
Section | Actif | Inactif
--------- + -------- + ----------
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 qui renvoie 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.
Comme vous devez de toute façon épeler toutes les colonnes d'une liste de définitions de colonnes (à l'exception des variantes prédéfinies ), il est généralement plus efficace de fournir une courte liste dans une expression comme illustré:crosstabN()
VALUES
$$VALUES ('Active'::text), ('Inactive')$$)
Ou (pas dans le manuel):
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
J'ai utilisé la cotation en dollars pour faciliter la cotation.
Vous pouvez même générer des colonnes avec différents 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 de sortie text
, date
, numeric
etc. pour les attributs respectifs. Il y a un exemple de code à la fin du chapitre crosstab(text, text)
du manuel .
db <> violon ici
Exemples avancés
\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 la nourrir \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 uniquement d'une fonction de représentation côté client . Les lignes en entrée sont traitées légèrement différemment, elles ORDER BY
ne sont donc pas nécessaires. 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):
La réponse précédemment acceptée est obsolète.
La variante de la fonction crosstab(text, integer)
est obsolète. Le deuxième integer
paramètre est ignoré. Je cite le manuel actuel :
crosstab(text sql, int N)
...
Version obsolète de crosstab(text)
. Le paramètre N
est désormais ignoré, car le nombre de colonnes de valeur est toujours déterminé par la requête appelante
Casting et renommage inutiles.
Il échoue si une ligne n'a pas tous les attributs. Voir la variante sûre avec deux paramètres d'entrée ci-dessus pour gérer correctement les attributs manquants.
ORDER BY
est requis sous la forme à un paramètre de crosstab()
. Le manuel:
En pratique, la requête SQL doit toujours spécifier ORDER BY 1,2
pour garantir que les lignes d'entrée sont correctement ordonnées