子查询作为mysql中的生成列?

Posted

技术标签:

【中文标题】子查询作为mysql中的生成列?【英文标题】:Subquery as generated column in mysql? 【发布时间】:2016-11-21 18:16:21 【问题描述】:

我可以在表 A 中创建一个生成的列,将表 B 中的列与表 A 中行的 tableA_id 相加吗?

假设我有一张家庭表和一张儿童表。我想要每个家庭孩子的年龄总和。

ALTER TABLE people.families 
ADD COLUMN sumofages DECIMAL(10,2) GENERATED ALWAYS AS 
(SELECT SUM(age) FROM people.children WHERE family_id = people.families.id) STORED;

ERROR 3102: Expression of generated column 'sumofages' contains a disallowed function.

我也无法将其保存为 VIRTUAL 类型。我在这里做错了什么?

ALTER TABLE people.families 
ADD COLUMN sumofages DECIMAL(10,2) GENERATED ALWAYS AS 
(SELECT SUM(age) FROM people.children WHERE family_id = people.families.id) VIRTUAL;

ERROR 3102: Expression of generated column 'sumofages' contains a disallowed function.

我不知道禁止使用哪个功能。 SUM 似乎不是。也许选择?

【问题讨论】:

我认为 mysql 不支持您尝试执行的操作。你会对UPDATE 声明感到满意吗? 我目前使用子选择。我不想实际存储数据,我只是有过多的子选择,我无法从 MySQL 中找到明确的文档来表明它不受支持。在 MariaDB 中,文档表明它不受支持,并且生成的表达式只能包含当前行中的数据。我只是想确定我没有遗漏什么。 【参考方案1】:

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

生成的列表达式必须遵守以下规则。一个 如果表达式包含不允许的构造,则会发生错误。

子查询、参数、变量、存储函数和用户自定义 不允许使用函数。

生成列的表达式可以引用同一行中的列是合理的。生成的列不能使用子查询,也不能引用其他表,或者具有不确定输出的函数。

假设生成的列确实支持跨表引用。特别考虑STORED生成列的情况。

如果您更新一个表,MySQL 还必须更新数据库中其他地方生成的列中的任何引用,如果它们引用了您更新的行。 MySQL 跟踪所有这些引用将是复杂且昂贵的。

然后考虑通过存储函数添加间接引用。

然后考虑您的更新是在事务中对 InnoDB 表的更新,但生成的列可能在非事务(MyISAM、MEMORY、ARCHIVE 等)表中。当您进行更新时,您的更新是否应该反映在这些生成的列中?如果你回滚呢?您的更新是否应该在您提交时反映出来?那么 MySQL 应该如何“排队”更改以应用于这些表呢?如果多个事务提交影响生成的列引用的更新怎么办?哪一个应该获胜,最后应用更改的还是最后提交的?

由于这些原因,允许生成的列引用同一个表中同一行的列以外的任何内容是不切实际或有效的。

【讨论】:

【参考方案2】:

计算列的想法是从记录中的其他列中获取数据,例如将国家/地区代码与邮政编码结合起来,这样您就可以存储 DE 和 12345,然后您会得到可以在地址中使用的 DE-12345。

然而,你想要做的是完全不同的事情。您正在访问另一个表中的数据。但是该表的数据可能会发生变化,因此在访问同一条记录时,您可能会突然得到完全不同的结果。计算列应包含确定性值,因此只要您的记录数据不更改,它们就不会更改。在这方面我不了解 MySQL,但它可能会禁止非确定性数据,例如您的子查询。

您真正在寻找的是一个视图。视图可以组合来自不同表的选择,就像您希望它发生一样。所以使用

create view familydata as
(
  select f.*, sum(c.age) as sumofages
  from families f
  join children c on c.family_id = f.id
  group by f.id
);

create view familydata as
(
  select f.*,
  (
    select sum(age)
    from children c
    where c.family_id = f.id
  ) as sumofages
  from families f
);

我希望我的语法正确。

【讨论】:

以上是关于子查询作为mysql中的生成列?的主要内容,如果未能解决你的问题,请参考以下文章

mysql子查询中的未知列

MySQL - 如何将子查询中的列别名用于另一个子查询?

MySQL的子查询中FROM和EXISTS子句的使用教程

mysql中的子查询将一列用于两个不同的结果

JOIN 语法中的 MySQL 相关子查询

从 SQL SELECT 中的子查询和 ROW_NUMBER 窗口函数生成“平均”列