2011-03-07 22 views
34

Dada la siguiente tabla:¿Columna calculada desde otra columna?

id | value 
-------------- 
1  6 
2  70 

¿Hay una manera de agregar una columna que se calcula automáticamente en función de otra columna en la misma mesa? Como una VISTA, pero parte de la misma mesa. Como ejemplo, calculated sería la mitad de value. Calculated se debe actualizar automáticamente cuando value cambia, al igual que una VISTA sería.

El resultado sería:

id | value | calculated 
----------------------- 
1  6  3 
2  70  35 
+6

¿Por qué no utilizar una VISTA? –

+0

Las columnas calculadas persistentes (a.k.a., almacenadas) a menudo son más económicas de leer porque se almacenan al igual que otras columnas. Incluso pueden ser indexados. –

+0

Las columnas calculadas no persistentes son solo una función de conveniencia. A menudo funciona mejor que las vistas cuando se trata de ORM. –

Respuesta

24

Si se trata de una selección, puede hacerlo como:

SELECT id, value, (value/2) AS calculated FROM mytable 

Si no, puede también primero modificar la tabla para agregar la columna desaparecidos y y luego hacer una consulta de actualización para calcular los valores para la nueva columna como:

UPDATE mytable SET calculated = value/2; 

Si tiene que ser automático, y yo Tu versión de MySQL lo permite, puedes probar con triggers

+6

Sí, eso es un SELECCIONADO, sin agregar una columna a la tabla. – Matthew

+4

¿Se puede usar esa columna 'calculada' para ejecutar más cálculos en la misma consulta? Me gusta ('calculate' * 2) AS' double_calculated'? – Piero

4

Si quieres agregar una columna a tu tabla que se actualiza automáticamente a la mitad de alguna otra columna, puedes hacer eso con un disparador.

Pero creo que la respuesta ya propuesta es una mejor manera de hacerlo.

seco gatillo codificado:

CREATE TRIGGER halfcolumn_insert AFTER INSERT ON table 
    FOR EACH ROW BEGIN 
    UPDATE table SET calculated = value/2 WHERE id = NEW.id; 
    END; 
CREATE TRIGGER halfcolumn_update AFTER UPDATE ON table 
    FOR EACH ROW BEGIN 
    UPDATE table SET calculated = value/2 WHERE id = NEW.id; 
    END; 

No creo que se puede hacer sólo un disparador, ya que el evento hay que responder a son diferentes.

+0

Gracias. En este caso, también deberíamos considerar Eliminar? –

19

La respuesta de @krtek va en la dirección correcta, pero tiene un par de problemas.

La mala noticia es que utilizar UPDATE en un desencadenante en la misma tabla no funcionará. La buena noticia es que no es necesario; hay un objeto NUEVO con el que puede operar incluso antes de tocar la mesa.

El disparador se convierte en:

CREATE TRIGGER halfcolumn_update BEFORE UPDATE ON my_table 
    FOR EACH ROW BEGIN 
    SET NEW.calculated = NEW.value/2; 
    END; 

Tenga en cuenta también que el begin ... end; la sintaxis tiene que ser analizada con un delimitador diferente en efecto. Todo el shebang se convierte en:

DELIMITER | 

CREATE TRIGGER halfcolumn_insert BEFORE INSERT ON my_table 
    FOR EACH ROW BEGIN 
    SET NEW.calculated = NEW.value/2; 
    END; 
| 

CREATE TRIGGER halfcolumn_update BEFORE UPDATE ON my_table 
    FOR EACH ROW BEGIN 
    SET NEW.calculated = NEW.value/2; 
    END; 
| 

DELIMITER ; 
+2

Nota: En el código anterior, reemplace la palabra "tabla" con su nombre de tabla. Pensé que el autor simplemente olvidó el nombre de la tabla y lo agregó después de "ON table" y desperdició unos minutos en eso. – Bloodboiler

+0

Buena llamada @Bloodboiler - Modifiqué el fragmento para ser un poco más claro. – Jerry

18

columna generada es uno de los buen enfoque para la versión de MySQL que es 5.7.6 y superiores.

Hay dos tipos de columnas generadas:

  • virtual (por defecto) - columna se calculará sobre la marcha cuando un registro se lee de una tabla
  • almacenados - se calculará la columna cuando una nuevo registro se escribe/modificada en la tabla

Ambos tipos pueden tener restricciones NOT NULL, pero sólo una columna generada almacenada puede ser parte de un índice.

Para el caso actual, vamos a usar la columna generada almacenada. Para implementar he considerado que tanto de los valores necesarios para el cálculo están presentes en la tabla

cantidad
CREATE TABLE order_details (price DOUBLE, quantity INT, amount DOUBLE AS (price * quantity)); 

INSERT INTO order_details (price, quantity) VALUES(100,1),(300,4),(60,8); 

aparecerá automáticamente en la tabla y se puede acceder a él directamente, también tenga en cuenta que cada vez que se actualice cualquiera de las columnas , la cantidad también se actualizará.

+2

creo que esta debería ser la respuesta aceptada –

+0

De acuerdo, esta es la respuesta correcta. –

+0

De acuerdo con la documentación, esto solo funciona con el motor de almacenamiento NDB, no con InnoDB – cliffordheath

2

Espero que esto ayude a muchas personas a acceder a este artículo. Si necesita una columna calculada, ¿por qué no simplemente exponer sus columnas deseadas en una vista? No solo guarde datos o sobrecargue el rendimiento con desencadenantes ... simplemente exponga los datos que necesita formateados/calculados en una vista.

Espero que esto ayude ...

Cuestiones relacionadas