使用一个子查询更新多个列

时间:2016-01-23 07:45:36

标签: sqlite sql-update aggregate

我在sqlite中有一个经典的父子关系:

create table tq84_parent (
  id                int primary key,
  avg_val           float,
  min_val           float,
  max_val           float
);

create table tq84_child (
  id_parent         int references tq84_parent,
  val               int
);

填写如下

insert into tq84_parent (id) values(1);
insert into tq84_parent (id) values(2);

insert into tq84_child values (1,  1);
insert into tq84_child values (1,  2);
insert into tq84_child values (1,  3);

insert into tq84_child values (2,  6);
insert into tq84_child values (2,  7);
insert into tq84_child values (2,  8);
insert into tq84_child values (2,  9);
insert into tq84_child values (2, 10);

现在,我想更新tq84_parent,其列avg_valmin_valmax_val反映其子表的相应聚合值。

我可以用这句话来实现这个目标:

update 
  tq84_parent
set
  avg_val = (select avg(val) from tq84_child where id_parent = id),
  min_val = (select min(val) from tq84_child where id_parent = id),
  max_val = (select max(val) from tq84_child where id_parent = id);

根据需要,结果是:

.mode columns

select * from tq84_parent;

1           2.0         1.0         3.0
2           8.0         6.0         10.0

但是,我担心这样的声明的表现不是最佳的,因为tq84_parenttq84_child中的记录数量都会增长,因为几乎相同的查询是三次而不是一次。

所以,我想和

这样的东西一起去
update
  tq84_parent
set
 (
  avg_val,
  min_val,
  max_val
 )
= (select
     avg(val),
     min(val),
     max(val)
   from
     tq84_child
   where
     id_parent = id
);

哪个不起作用。

那么,有没有办法重写我的查询?

2 个答案:

答案 0 :(得分:1)

由于idid_parent是主键和外键,因此id是唯一的,id_parent始终引用现有ID。

这意味着您可以使用REPLACE来更改表,因为始终违反了唯一键(也就是说不会进行插入),REPLACE可以获取子查询并一次设置多个列;

REPLACE INTO tq84_parent (id, avg_val, min_val, max_val)
  SELECT id_parent, AVG(val), MIN(val), MAX(val)
  FROM tq84_child
  GROUP BY id_parent;

An SQLfiddle to test with

注意:正如CL指出的那样,未在查询中设置的字段将具有其默认值,因为行已被替换,而不是已更新。这意味着如果表中有其他字段需要保持不变,那么旧方法仍然是这样做的。

答案 1 :(得分:0)

查询执行的实际速度主要取决于需要完成的磁盘I / O量。

使用上面显示的数据库模式,每个子查询都需要扫描整个表。 如果在计算聚合值所需的所有列上都有覆盖索引,则每个子查询只需要扫描索引的一小部分,因此实际上,在为多个子查询执行多个子查询时,数据保证已经存在于缓存中。相同的ID:

CREATE INDEX xxx ON tq84_child(id_parent, val);