(MySQL)使用在更新的查询中计算的值更新多行

时间:2014-06-19 23:03:35

标签: mysql sql-update subquery

我希望更新一些表的行,univ_members,以他们的宇宙#来区分它们的百分位数或等级。该pctile值在子查询中计算。子查询本身工作正常,但是当提供给更新时,“子查询返回多行”失败。代码块中的第23行是违规表达式。 (这段代码是从here (stackoverflow)here (a poster's blog)收集的,最终(我认为)来自一本书,“高性能MySQL”,Schwartz,Zaitsev,Tkachenko,p.648 et seq。第3版)

我无法让它与更新一起工作。我开始怀疑,在阅读了有关更新的30个不同帖子和“子查询返回多行”之后,这不是在一个复杂的查询中,MySQL是可能的,而我需要编写一个proc来通过循环来完成它。 可以在查询中在MySQL中完成,还是需要循环?如果有查询,该怎么做? 我想提一下,这个查询不使用自联接这一事实对我而言对性能非常有价值。我的生产表以112,000个记录开头,可能会增加到400万个。

第11行是计算pctile值的地方。第13行是初始化计数器变量的地方(显然只有一次)。内部选择命令由std_dev_rank(第15行)对每个pid的$ vol(美元 - 体积)的标准差进行排序,两者都是先前计算的。 @curr最初被设置为它们中的最高位置(第10行),然后是13,与前一个相比,因此给出了相应的排名。一些简单的算术随之而来。 我省略了你自己尝试的变量定义和其他细节,但我确实包含了univ_members表(第19行)。

如果您感兴趣,这超出了我的股票动量/价格估算和预测计划。 $ -volume是流动性的衡量标准。这是为了准备选择适合进一步检查的股票(pids)。 (每个'宇宙'都是跨时间的股票,经常重叠。这就是为什么表格可以超过现有股票的数量。)

1  create temporary table um like univ_members;
2  insert into um select * from univ_members where id_universe = @univ_num;
3
4  update um
5    set pctile =
6    (
7    select pctile from(
8      select
9        @prev := @curr,
10       @curr := std_dev_rank,
11       (100- ((@rank := IF(@prev= @curr, @rank, @rank+1))* @recs_per_pctile)) AS pctile
12       from univ_members
13         ,(select @curr := null, @prev := null, @rank := 0) x
14       where id_universe = @univ_num
15       order by std_dev_rank desc) q
16   where id_universe = @univ_num);
17
18 -- the univ_members table
19 create table univ_members
20 (
21   id_universe    smallint(5) unsigned not null,
22   pid            char(8) not null,
23   $vol           double unsigned default null,
24   coef_cor       double default null, -- 'distance' from median $vol
25   pctile         double unsigned default null, -- another 'distance' measure
26   std_dev_rank   double default null, -- individual std dev bracket
27
28   primary key pk_univ_members (id_universe, pid),
29   key k_$vol ($vol)
30 ) engine=InnoDB;

1 个答案:

答案 0 :(得分:3)

您需要让子查询返回主键和百分位数。然后,您可以加入子查询并更新相应行中的列:

UPDATE um
JOIN (select id_universe, pid,
             @prev := @curr,
             @curr := std_dev_rank,
             (100- ((@rank := IF(@prev= @curr, @rank, @rank+1))* @recs_per_pctile)) AS pctile
      from univ_members
           ,(select @curr := null, @prev := null, @rank := 0) x
      where id_universe = @univ_num
      order by std_dev_rank desc) q
SET um.pctile = q.pctile
WHERE um.id_universe = q.id_universe AND um.pid = q.pid