从另一列计算的列?

Posted

技术标签:

【中文标题】从另一列计算的列?【英文标题】:Column calculated from another column? 【发布时间】:2011-03-07 16:17:32 【问题描述】:

给定下表:

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

有没有办法添加一个根据同一个表中的另一列自动计算的列?类似于 VIEW,但属于同一张表。例如,calculated 将是value 的一半。 Calculated 应该在 value 更改时自动更新,就像 VIEW 一样。

结果是:

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

【问题讨论】:

那么为什么不使用视图呢? 持久(又名存储)计算列的读取成本通常较低,因为它们的存储方式与其他列一样。它们甚至可以被编入索引。 非持久计算列只是一个方便的功能。在处理 ORM 时,它通常比视图效果更好。 【参考方案1】:

Generated Column 是 5.7.6 及更高版本的 mysql 版本的好方法之一。

生成的列有两种:

虚拟(默认) - 列将在运行时计算 从表中读取记录 已存储 - 列将在 新记录在表中写入/更新

这两种类型都可以有 NOT NULL 限制,但只有存储的 Generated Column 可以是索引的一部分。

对于当前情况,我们将使用存储生成的列。为了实现,我认为计算所需的两个值都存在于表中

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

amount 将自动在表格中弹出,您可以直接访问它,还请注意,每当您更新任何列时,amount 也会随之更新。

【讨论】:

根据文档,这只适用于 NDB 存储引擎,不适用于 InnoDB @cliffordheath - 你错了。我使用 mySQL 5.7、InnoDB 引擎和生成的列创建了示例 sql fiddle - 它工作正常:db-fiddle。您所指的 mySQL doc 确实具有误导性,但假设它应该读作:“从 mySQL 5.7 和 NDB 存储引擎开始支持从 MySQL NDB Cluster 7.5.3 开始生成的列” @user2988142 很高兴知道。不过,即使您的措辞也可能模棱两可。也许提交文档错误报告? 我正在尝试通过 MySQL 使用自动生成的列功能,同时尝试使用 JDBC 与数据库交互。 - 自动生成的单元格,它应该根据框架查询实际显示结果,该单元格是可编辑的,不会阻止自动生成和出错。请让我知道我需要对该行的代码进行哪些更改才能自动填充。另外,由于在 Mysql 5.7 中引入了自动生成功能,但我使用的是 5.1 版本的连接器/驱动程序。会不会是个问题?? AWS Aurora MySQL 实例在使用存储列(派生)作为复合索引的一部分时崩溃。 mysql #23533396【参考方案2】:

如果是选择,你可以这样做:

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

否则,您也可以先更改表以添加缺少的列,然后执行 UPDATE 查询以计算新列的值:

UPDATE mytable SET calculated = value/2;

如果它必须是自动的,并且您的 MySQL 版本允许,您可以尝试使用triggers

【讨论】:

是的,这是一个 SELECT,而不是向表中添加列。 您可以使用calculated 列在同一个查询中运行进一步的计算吗?喜欢 (calculated*2) AS double_calculated ? @ZurabWeb 可以,但在外部选择(嵌套选择语句可用)【参考方案3】:

MySQL 5.7 支持计算列。他们称之为“生成的列”,语法有点奇怪,但它支持我在其他数据库中看到的相同选项。

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

【讨论】:

不幸的是,“生成的列”不是 ISO SQL 标准的一部分。看起来唯一的“ISO SQL”解决方案是使用 VIEW。【参考方案4】:

@krtek 的回答方向正确,但有几个问题。

坏消息是在同一个表的触发器中使用 UPDATE 是行不通的。好消息是没有必要。有一个 NEW 对象,您甚至可以在触摸表之前对其进行操作。

触发器变成:

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

还要注意 BEGIN...END;语法必须使用不同的分隔符进行解析。整个shebang变成:

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 ;

【讨论】:

注意:在上面的代码中,用你的表名替换“table”这个词。我以为作者只是忘记了表名,并在“ON table”之后添加了它,浪费了几分钟。 很好的电话@Bloodboiler - 我修改了 sn-p 更清晰一点。 请注意,这么多年过去了,MySQL 已经提出了一种更优雅的方式来完成这项任务。这个答案仍然有效,但有一些很好的论据反对使用触发器。如果使用 Abhishek Gupta 的答案对您来说很实用,那么您最终会得到一个更易于维护的系统。【参考方案5】:

您可以使用 MYSQL 5.7 中生成的列。

示例用法:

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

虚拟 / 存储

虚拟:从表中读取记录时动态计算(默认) Stored:在新记录插入/更新时计算 表

【讨论】:

【参考方案6】:

如果您想在表格中添加一列,该列会自动更新为其他列的一半,您可以使用触发器来执行此操作。

但我认为已经提出的答案是更好的方法。

干编码触发器:

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;

我认为你不能只触发一个触发器,因为我们必须响应的事件是不同的。

【讨论】:

谢谢。在这种情况下,我们也应该考虑删除?【参考方案7】:

我希望这仍然可以帮助尽可能多的人阅读这篇文章。如果您需要一个计算列,为什么不在视图中公开您想要的列呢?不要只保存数据或使用触发器超载性能...只需在视图中公开您需要已格式化/计算的数据。

希望这会有所帮助...

【讨论】:

这取决于,当 OLAP 解决方案的开销太大时,您可能希望添加具有舍入值的列以用于快速报告目的(因此分组聚合总和与 CRM / ERP 的数量相同或银行账户)。如果计算涉及的不仅仅是简单的计算,例如销售利润计算,或者需要连接其他表来进行计算,那么存储这些值可以加快报告速度。与其在需要报告时将所有数据打乱,不如在插入时手头有所有数据时插入值。

以上是关于从另一列计算的列?的主要内容,如果未能解决你的问题,请参考以下文章

我需要使用索引和匹配从另一列条件匹配的列中提取数据

如何计算另一列中特定值的列的平均值?

计算由另一列值分组的列值在 pandas 数据框中的共现

在数据框中创建列,按因子级别从另一列中采样

redshift update 命令从另一列设置值,该列名是标识符

计算重复数量并将它们放在数据框的列中