Columnas calculadas / calculadas / virtuales / derivadas en PostgreSQL

113

¿PostgreSQL admite columnas calculadas / calculadas, como MS SQL Server? No puedo encontrar nada en los documentos, pero como esta función está incluida en muchos otros DBMS, pensé que podría estar perdiendo algo.

Por ejemplo: http://msdn.microsoft.com/en-us/library/ms191250.aspx

Mike Chamberlain
fuente
Con la expresión de subconsulta lateral (función de Postgres), puede agregar fácilmente más columnas a cada fila.
Victor

Respuestas:

139

Las columnas generadas hasta Postgres 11 no son compatibles, como se define en el estándar SQL e implementado por algunos RDBMS, incluidos DB2, MySQL y Oracle. Ni las similares "columnas calculadas" de SQL Server.

STOREDLas columnas generadas se introducen con Postgres 12 . Ejemplo trivial:

CREATE TABLE tbl (
  int1    int
, int2    int
, product bigint GENERATED ALWAYS AS (int1 * int2) STORED
);

db <> violín aquí

VIRTUALlas columnas generadas pueden venir con una de las siguientes iteraciones. (Todavía no en Postgres 13).

Relacionado:


Hasta entonces , puede emular VIRTUALcolumnas generadas con una función usando la notación de atributo ( tbl.col) que se ve y funciona de manera muy similar a una columna generada virtual . Esa es una rareza de sintaxis que existe en Postgres por razones históricas y que encaja en el caso. Esta respuesta relacionada tiene ejemplos de código :

Sin SELECT * FROM tblembargo, la expresión (que parece una columna) no se incluye en un . Siempre debes enumerarlo explícitamente.

También se puede admitir con un índice de expresión coincidente , siempre que la función sea IMMUTABLE. Me gusta:

CREATE FUNCTION col(tbl) ... AS ...  -- your computed expression here
CREATE INDEX ON tbl(col(tbl));

Alternativas

Alternativamente, puede implementar una funcionalidad similar con a VIEW, opcionalmente junto con índices de expresión. Luego SELECT *puede incluir la columna generada.

Las STOREDcolumnas calculadas "persistentes" ( ) se pueden implementar con disparadores de una manera funcionalmente idéntica.

Las vistas materializadas son un concepto estrechamente relacionado, implementado desde Postgres 9.3 .
En versiones anteriores, se pueden administrar MV manualmente.

Erwin Brandstetter
fuente
Dependiendo de la cantidad de datos que esté cargando a la vez, el disparador puede ralentizar drásticamente las cosas. Es posible que desee considerar actualizaciones en su lugar.
sam yi
1
Estas soluciones son prácticamente inútiles (sin grandes cambios de código en una base de código sin casos de prueba) al migrar de Oracle a Postgres. ¿Existen soluciones desde la perspectiva de la migración?
happybuddha
@happybuddha: haga su pregunta como pregunta. Los comentarios no son el lugar. Siempre puede vincular a esta pregunta para el contexto (y agregar un comentario aquí para llamar mi atención y vincular a la pregunta relacionada).
Erwin Brandstetter
4
La funcionalidad está en desarrollo en este momento: commitfest.postgresql.org/16/1443
r90t
1
@cryanbhu: Depende de los detalles de su configuración y requisitos. Puede hacer una nueva pregunta con la información necesaria.
Erwin Brandstetter
32

¡¡Sí tu puedes!! La solución debe ser fácil, segura y eficaz ...

Soy nuevo en postgresql, pero parece que puede crear columnas calculadas usando un índice de expresión , emparejado con una vista (la vista es opcional, pero hace la vida un poco más fácil).

Supongamos que mi cálculo es md5(some_string_field), luego creo el índice como:

CREATE INDEX some_string_field_md5_index ON some_table(MD5(some_string_field));

Ahora, cualquier consulta que actúe MD5(some_string_field)utilizará el índice en lugar de calcularlo desde cero. Por ejemplo:

SELECT MAX(some_field) FROM some_table GROUP BY MD5(some_string_field);

Puedes comprobar esto con explicar .

Sin embargo, en este punto, confía en que los usuarios de la tabla sepan exactamente cómo construir la columna. Para hacer la vida más fácil, puede crear una VIEWversión aumentada de la tabla original, agregando el valor calculado como una nueva columna:

CREATE VIEW some_table_augmented AS 
   SELECT *, MD5(some_string_field) as some_string_field_md5 from some_table;

Ahora, cualquier consulta que utilice some_table_augmentedpodrá utilizarse some_string_field_md5sin preocuparse por cómo funciona ... simplemente obtienen un buen rendimiento. La vista no copia ningún dato de la tabla original, por lo que es buena tanto en cuanto a memoria como a rendimiento. Sin embargo, tenga en cuenta que no puede actualizar / insertar en una vista, solo en la tabla de origen, pero si realmente lo desea, creo que puede redirigir las inserciones y actualizaciones a la tabla de origen utilizando reglas (podría estar equivocado en ese último punto ya que Yo nunca lo he probado).

Editar: parece que si la consulta involucra índices en competencia, el motor del planificador a veces puede no usar el índice de expresión en absoluto. La elección parece depender de los datos.

dan-man
fuente
1
¿Podría explicar o dar un ejemplo de if the query involves competing indices?
dvtan
17

¡Una forma de hacer esto es con un gatillo!

CREATE TABLE computed(
    one SERIAL,
    two INT NOT NULL
);

CREATE OR REPLACE FUNCTION computed_two_trg()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
AS $BODY$
BEGIN
    NEW.two = NEW.one * 2;

    RETURN NEW;
END
$BODY$;

CREATE TRIGGER computed_500
BEFORE INSERT OR UPDATE
ON computed
FOR EACH ROW
EXECUTE PROCEDURE computed_two_trg();

El disparador se activa antes de que se actualice o inserte la fila. Cambia el campo que queremos calcular de NEWregistro y luego devuelve ese registro.

Elmer
fuente
¿Cuándo se dispara realmente el gatillo? Ejecuté lo anterior e hice esto insert into computed values(1, 2); insert into computed values(4, 8); commit; select * from computed;y acaba de regresar: 1 2 y 4 8
happybuddha
2
intente que insert into computed(one) values(1); insert into computed(one) values(4); commit; select * from computed;el valor de la twocolumna se calculará automáticamente!
Elmer
8

PostgreSQL 12 admite columnas generadas:

¡Lanzamiento de PostgreSQL 12 Beta 1!

Columnas generadas

PostgreSQL 12 permite la creación de columnas generadas que calculan sus valores con una expresión utilizando el contenido de otras columnas. Esta función proporciona columnas generadas almacenadas, que se calculan en inserciones y actualizaciones y se guardan en el disco. Las columnas generadas virtuales, que se calculan solo cuando una columna se lee como parte de una consulta, aún no están implementadas.


Columnas generadas

Una columna generada es una columna especial que siempre se calcula a partir de otras columnas. Por tanto, es para columnas lo que es una vista para tablas.

CREATE TABLE people (
    ...,
    height_cm numeric,
    height_in numeric GENERATED ALWAYS AS (height_cm * 2.54) STORED
);

db <> demostración de violín

Lukasz Szozda
fuente
Artículo de blog: 2ndquadrant.com/en/blog/generated-columns-in-postgresql-12
Christophe Roussy
1

Bueno, no estoy seguro de si esto es lo que quiere decir, pero Posgres normalmente admite la sintaxis ETL "ficticia". Creé una columna vacía en la tabla y luego necesitaba llenarla con registros calculados según los valores en la fila.

UPDATE table01
SET column03 = column01*column02; /*e.g. for multiplication of 2 values*/
  1. Es tan tonto que sospecho que no es lo que estás buscando.
  2. Obviamente no es dinámico, lo ejecuta una vez. Pero no hay obstáculo para ponerlo en gatillo.
ďobo
fuente
0

Tengo un código que funciona y uso el término calculado, no estoy en postgresSQL puro aunque ejecutamos en PADB

así es como se usa

create table some_table as
    select  category, 
            txn_type,
            indiv_id, 
            accum_trip_flag,
            max(first_true_origin) as true_origin,
            max(first_true_dest ) as true_destination,
            max(id) as id,
            count(id) as tkts_cnt,
            (case when calculated tkts_cnt=1 then 1 else 0 end) as one_way
    from some_rando_table
    group by 1,2,3,4    ;
Cableado604
fuente
¿Qué es PADB exactamente?
Gherman
La base de datos analítica de ParAccel es vieja pero agradable ... en.wikipedia.org/wiki/ParAccel
Wired604
Pero, ¿cómo se relaciona con una pregunta sobre Postgres? Seguro que hay muchas bases de datos compatibles con columnas calculadas.
Gherman
Ah, lo siento, no me tomé el tiempo para volver al contexto ... ¡PADB se basa en el postgress!
Wired604
-6

Una solución ligera con restricción de comprobación:

CREATE TABLE example (
    discriminator INTEGER DEFAULT 0 NOT NULL CHECK (discriminator = 0)
);
cinereo
fuente
6
¿Cómo se relaciona esto con el concepto de columna calculada? ¿Te importaría explicarme?
Erwin Brandstetter
4
De acuerdo, no está directamente relacionado. Pero es una sustitución de un caso simple en el que solo necesita hacer algo como field as 1 persisted.
cinereo
2
De hecho, una descripción hubiera sido buena. Creo que esta respuesta es que si el cálculo se puede hacer con la cláusula predeterminada, entonces puede usar una restricción predeterminada y una de verificación para evitar que alguien cambie el valor.
Ross Bradbury
@Ross Bradbury: De acuerdo, pero eso solo funciona para insertar. No funcionaría si se actualizara una columna dependiente.
Stefan Steiger