PostgreSQL: columnas generadas


16

¿PostgreSQL admite columnas generadas ? También se conoce como columnas virtuales . Estoy no hablando de IDENTITYcolumnas .

No puedo encontrar ninguna información sobre esta característica notable, pero sé que está disponible en SQL Server y en las últimas versiones de MariaDB y MySQL.

La característica se menciona en el estándar SQL: 2003 , y hubo una discusión en los foros de PostgreSQL alrededor de 2006, pero no puedo encontrar nada sustancial al respecto.

Existe cierta discusión sobre SO, pero ahora es bastante antiguo, por lo que puede estar desactualizado.


2
Esta respuesta relacionada de 2012 sobre SO puede ser útil: stackoverflow.com/questions/11165450/… Sigue siendo válida.
Erwin Brandstetter

@ErwinBrandstetter Lo siento, me perdí este comentario. Es un truco útil. Gracias.
Manngo

Respuestas:


17

No estoy seguro de si esto es lo que desea, pero la notación de atributos row.full_namey la notación de funciones full_name(row)son equivalentes en postgresql.

Eso significa que tomas una mesa

CREATE TABLE people (
  first_name text,
  last_name text
);

y una función:

CREATE FUNCTION full_name(people) RETURNS text AS $$
  SELECT $1.first_name || ' ' || $1.last_name;
$$ LANGUAGE SQL;

y llámalo así:

select full_name from people

Es eso lo que necesita?

Para acelerar las cosas, puede crear un índice de expresión:

CREATE INDEX people_full_name_idx ON people
USING GIN (to_tsvector('english', full_name(people)));

O almacene todo en una vista materializada.

Ejemplo tomado de aquí: http://bernardoamc.github.io/sql/2015/05/11/postgres-virtual-columns/


2
Esta es la respuesta correcta. Vea, por ejemplo, cómo Postgrest se refiere a este comportamiento como "columnas calculadas".
fiatjaf

Typo, creo: ¿la selección debe ser de select people.full_name from peopleo select full_name(people) from people?
Barguast

No, funciona así. El prefijo en "select people.full_name from people" se puede omitir como en SQL normal.
Fabian Zeindl

Perdí esta respuesta, viniendo, por así decirlo, mucho después de haberme rendido. Gracias por la sugerencia.
Manngo

1
¿Podrías cambiar la respuesta aceptada entonces?
Fabian Zeindl

6

No, esto actualmente (a partir de Postgres 9.6) no es compatible.

La única solución es usar un disparador o una vista si es un cálculo simple que no necesita indexar.


Ratas Supongo que podría optar por una vista materializada si necesito el rendimiento. He agregado una solicitud para la función, ya que está disponible en la competencia.
Manngo

1
No hay necesidad de una MVIEW. Una columna con un disparador también le permitirá indexar el contenido de la columna
a_horse_with_no_name

Tengo un problema filosófico con el almacenamiento de columnas reales adicionales que son básicamente una repetición de los otros datos. Des-normaliza la mesa.
Manngo

55
Bueno, una columna calculada es exactamente eso: almacenar datos desnormalizados. Cómo se genera el valor de la columna calculada no importa. No veo una diferencia conceptual entre una columna calculada "real" y una que se genera a través de un disparador
a_horse_with_no_name

Otra solución (para algunos casos) es indexar una expresión.
ypercubeᵀᴹ

5

Si: GENERATED ALWAYS AS … STORED

Postgres 12 agrega la funcionalidad para columnas generadas, como se menciona en el estándar SQL: 2003 .

El valor se genera en el momento de un INSERTo UPDATE, luego se almacena con la fila como cualquier otro valor.

Un generado debe basarse en una columna base de la misma tabla, o en una función inmutable .

La sintaxis es simple, una cláusula sobre CREATE TABLE:

GENERATED ALWAYS AS ( generation_expr ) STORED 

Ejemplo:

CREATE TABLE people (
    ...,
    height_cm NUMERIC,
    height_in NUMERIC GENERATED ALWAYS AS ( height_cm / 2.54 ) STORED
);

caracteristicas:

  • Puede ser indexado.
  • Parte del estándar SQL.

Advertencias:

  • Basado en columnas de la misma tabla (tablas no relacionadas)
  • No se permite la partición (no puede ser parte de una clave de partición)
  • Datos siempre escritos en fila, ocupando espacio en el almacenamiento
    • La función futura podría ofrecer VIRTUAL para valores calculados sobre la marcha sin almacenamiento
  • Generación profunda profunda (use una columna base, no otra columna generada)
  • No hay GENERADO POR DEFECTO (no puede anular el valor)
  • No se puede acceder a gen-col ANTES del disparador (valor aún no determinado)
  • Las funciones deben ser inmutables.

Ver:


Gracias por esa información Veo que la versión 12 aún no se ha lanzado completamente, pero estoy deseando que llegue. Observo que PostgreSQL usa la sintaxis más estándar, pero por lo demás es lo mismo que MSSQL. Encontré las especificaciones SQL2003 aquí: sigmodrecord.org/publications/sigmodRecord/0403/… . Siempre he dicho que SQL es un estándar de movimiento muy lento, y las implementaciones de DBMS son incluso lentas.
Manngo

0

Dependiendo de su caso de uso, puede lograr este tipo de comportamiento declarando una nueva columna y rellenándola con un activador en la inserción / actualización.

Si fuera posible, usaría las respuestas anteriores para evitar la duplicación de datos que podrían derivarse de lo que ya tiene, pero hace el truco y podría ser útil para los campos derivados computacionalmente intensivos que desea calcular una vez y guardar.

Consideré este enfoque para tratar un problema en el que a veces solo tenía 15 dígitos de una clave de 18 dígitos (los últimos 3 dígitos son solo una suma de verificación) pero quería poder hacer cumplir una relación de clave externa.

Documentos de PG sobre desencadenantes: https://www.postgresql.org/docs/9.6/sql-createtrigger.html

Ejemplo de W3: https://www.w3resource.com/PostgreSQL/postgresql-triggers.php

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.