95 votes

Colonne calculée à partir d'une autre colonne ?

Étant donné le tableau suivant :

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

Existe-t-il un moyen d'ajouter une colonne qui est automatiquement calculée sur la base d'une autre colonne dans le même tableau ? Comme une VIEW, mais faisant partie de la même table. Par exemple, calculated serait la moitié de value . Calculated devrait être automatiquement mis à jour lorsque value des changements, tout comme le serait un VIEW.

Le résultat serait :

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

6 votes

Alors pourquoi ne pas utiliser un VIEW ?

5 votes

Les colonnes calculées persistantes (c'est-à-dire stockées) sont souvent moins chères à lire car elles sont stockées comme les autres colonnes. Elles peuvent même être indexées.

2 votes

Les colonnes calculées non persistantes ne sont qu'une fonctionnalité pratique. Elles fonctionnent souvent mieux que les vues lorsqu'on a affaire à des ORM.

84voto

Rockse Points 787

Generated Column est une des bonnes approches pour la version MySql 5.7.6 et plus.

Il existe deux types de colonnes générées :

  • Virtuel (par défaut) - la colonne sera calculée à la volée lorsqu'un enregistrement est lu à partir d'une table. enregistrement est lu à partir d'une table
  • Stocké - la colonne sera calculée lorsqu'un nouvel enregistrement est écrit/mise à jour dans la table

Les deux types peuvent avoir des restrictions NOT NULL, mais seule une colonne générée stockée peut faire partie d'un index.

Dans le cas présent, nous allons utiliser une colonne générée stockée. Pour la mise en œuvre, j'ai considéré que les deux valeurs requises pour le calcul sont présentes dans la table.

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);

Le montant apparaîtra automatiquement dans le tableau et vous pourrez y accéder directement. Notez également que si vous mettez à jour l'une des colonnes, le montant sera également mis à jour.

0 votes

Selon la documentation, cela ne fonctionne qu'avec le moteur de stockage NDB, et non InnoDB.

1 votes

@cliffordheath - vous avez tort. J'ai créé l'exemple sql fiddle avec mySQL 5.7, le moteur InnoDB et Generated Column - il fonctionne bien : db-fiddle . mySQL doc à laquelle vous faites référence est en effet trompeuse mais supposez qu'elle devrait se lire comme suit : "Les colonnes générées sont supportées à partir de mySQL 5.7 et le moteur de stockage NDB à partir de MySQL NDB Cluster 7.5.3".

1 votes

@user2988142 Bon à savoir. Même votre formulation est potentiellement ambiguë. Vous pourriez peut-être soumettre un rapport de bogue de documentation ?

51voto

MarvinLabs Points 13401

S'il s'agit d'une sélection, vous pouvez le faire comme :

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

Sinon, vous pouvez également modifier la table pour ajouter la colonne manquante, puis effectuer une requête UPDATE pour calculer les valeurs de la nouvelle colonne :

UPDATE mytable SET calculated = value/2;

Si cela doit être automatique, et que votre version de MySQL le permet, vous pouvez essayer avec déclencheurs

9 votes

Oui, c'est un SELECT, pas l'ajout d'une colonne à la table.

6 votes

Pouvez-vous utiliser ce calculated pour effectuer d'autres calculs dans la même requête ? Par exemple ( calculated *2) AS double_calculated ?

1 votes

@ZurabWeb vous pouvez, mais dans une sélection externe (les sélections imbriquées sont disponibles).

25voto

Jonathan Allen Points 23540

MySQL 5.7 prend en charge les colonnes calculées. Elles s'appellent "Generated Columns" et la syntaxe est un peu bizarre, mais elle supporte les mêmes options que celles que je vois dans d'autres bases de données.

https://dev.mysql.com/doc/refman/5.7/en/create-table.html#create-table-generated-columns

1 votes

Malheureusement, les "colonnes générées" ne font pas partie de la norme ISO SQL. Il semble que la seule solution "ISO SQL" serait d'utiliser un VIEW.

21voto

Jerry Points 1271

La réponse de @krtek va dans le bon sens, mais présente quelques problèmes.

La mauvaise nouvelle est que l'utilisation de UPDATE dans un trigger sur la même table ne fonctionnera pas. La bonne nouvelle est que ce n'est pas nécessaire ; il existe un objet NEW sur lequel vous pouvez opérer avant même de toucher la table.

Le déclencheur devient :

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

Notez également que la syntaxe BEGIN...END ; doit être analysée avec un délimiteur différent. L'ensemble devient :

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 ;

3 votes

Note : Dans le code ci-dessus, remplacez le mot "table" par le nom de votre table. Je pensais que l'auteur avait simplement oublié le nom de la table et l'avait ajouté après "ON table" et qu'il avait perdu quelques minutes pour cela.

0 votes

Bien vu, @Bloodboiler - J'ai modifié l'extrait pour être un peu plus clair.

1 votes

Notez que toutes ces années plus tard, MySQL a mis au point une méthode beaucoup plus élégante pour accomplir cette tâche. Cette réponse fonctionne toujours, mais il existe de bons arguments contre l'utilisation des triggers. Si la réponse d'Abhishek Gupta est plus pratique pour vous, vous obtiendrez un système plus facile à maintenir.

21voto

Hariboo Points 1

Vous pouvez utiliser les colonnes générées à partir de MYSQL 5.7.

Exemple d'utilisation :

ALTER TABLE tbl_test
ADD COLUMN calc_val INT 
GENERATED ALWAYS AS (((`column1` - 1) * 16) + `column2`) STORED;

VIRTUAL / STORED

  • Virtuel : calculé à la volée lorsqu'un enregistrement est lu depuis une table (par défaut)
  • Stocké : calculé lorsqu'un nouvel enregistrement est inséré/mis à jour dans la table. table

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X