Instale el módulo adicional tablefunc
una vez por base de datos, que proporciona la función crosstab()
. Desde Postgres 9.1 puedes usar CREATE EXTENSION
para eso:
CREATE EXTENSION IF NOT EXISTS tablefunc;
Caso de prueba mejorado
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
Forma simple: no se ajusta a los atributos faltantes
crosstab(text)
con 1 parámetro de entrada:
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);
Devoluciones:
Sección | Activo | Inactivo
--------- + -------- + ----------
A | 1 | 2
B | 4 | 5 5
C | 7 | - !!
- No hay necesidad de fundición y cambio de nombre.
- Tenga en cuenta lo incorrecto resultado para
C
: el valor 7
se completa para la primera columna. A veces, este comportamiento es deseable, pero no para este caso de uso.
- La forma simple también está limitada a exactamente tres columnas en la consulta de entrada proporcionada: nombre_fila , categoría , valor . No hay espacio para columnas adicionales. como en la alternativa de 2 parámetros a continuación.
Forma segura
crosstab(text, text)
con 2 parámetros de entrada:
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);
Devoluciones:
Sección | Activo | Inactivo
--------- + -------- + ----------
A | 1 | 2
B | 4 | 5 5
C | El | 7 - !!
Tenga en cuenta el resultado correcto para C
.
El segundo parámetro puede ser cualquier consulta que devuelva una fila por atributo que coincida con el orden de la definición de columna al final. A menudo querrá consultar atributos distintos de la tabla subyacente de esta manera:
'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
Eso está en el manual.
Como debe deletrear todas las columnas en una lista de definición de columna de todos modos (excepto las variantes predefinidas ), generalmente es más eficiente proporcionar una lista corta en una expresión como la demostrada:crosstabN()
VALUES
$$VALUES ('Active'::text), ('Inactive')$$)
O (no en el manual):
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
Utilicé las cotizaciones en dólares para facilitar las cotizaciones.
Puede incluso columnas de salida con diferentes tipos de datos con crosstab(text, text)
- siempre y cuando la representación de texto de la columna de valor es una entrada válida para el tipo de destino. De esta manera es posible que tenga los atributos de diferentes tipos y de salida text
, date
, numeric
etc para los atributos respectivos. Hay un ejemplo de código al final del capítulo.crosstab(text, text)
en el manual .
db <> violín aquí
Ejemplos avanzados
\crosstabview
en psql
Postgres 9.6 agregó este metacomando a su terminal interactiva predeterminada psql . Puede ejecutar la consulta que usaría como primer crosstab()
parámetro y alimentarla \crosstabview
(inmediatamente o en el siguiente paso). Me gusta:
db=> SELECT section, status, ct FROM tbl \crosstabview
Resultado similar al anterior, pero es una característica de representación exclusiva del lado del cliente . Las filas de entrada se tratan de forma ligeramente diferente, por ORDER BY
lo tanto, no es necesario. Detalles para \crosstabview
en el manual. Hay más ejemplos de código en la parte inferior de esa página.
Respuesta relacionada en dba.SE por Daniel Vérité (el autor de la función psql):
La respuesta previamente aceptada está desactualizada.
La variante de la función crosstab(text, integer)
está desactualizada. El segundo integer
parámetro se ignora. Cito el manual actual :
crosstab(text sql, int N)
...
Versión obsoleta de crosstab(text)
. El parámetro N
ahora se ignora, ya que la consulta de llamada siempre determina el número de columnas de valor.
Casting y cambio de nombre innecesarios.
Falla si una fila no tiene todos los atributos. Vea la variante segura con dos parámetros de entrada anteriores para manejar los atributos faltantes correctamente.
ORDER BY
se requiere en la forma de un parámetro de crosstab()
. El manual:
En la práctica, la consulta SQL siempre debe especificar ORDER BY 1,2
para garantizar que las filas de entrada estén ordenadas correctamente