分组更新

时间:2015-04-17 06:42:16

标签: oracle group-by partition

我对看似简单的UPDATE语句感到难过。

我正在寻找一个使用两个值的UPDATE。第一个(a)用于分组,第二个(b)用于查找相应组内的局部最小值。稍微多一点,b上有一个阈值:任何1或更小的值都保持不变。

drop table t1;
create table t1 (a number, b number);
insert into t1 values (1,0);
insert into t1 values (1,1);
insert into t1 values (2,1);
insert into t1 values (2,2);
insert into t1 values (3,1);
insert into t1 values (3,2);
insert into t1 values (3,3);
insert into t1 values (4,1);
insert into t1 values (4,3);
insert into t1 values (4,4);
insert into t1 values (4,5);


-- 1,0 -> 1,0
-- 1,1 -> 1,1
-- 2,1 -> 2,1
-- 2,2 -> 2,2
-- 3,1 -> 3,1
-- 3,2 -> 3,2
-- 3,3 -> 3,2  <-
-- 4,1 -> 4,1
-- 4,3 -> 4,3  <-
-- 4,4 -> 4,3  <-
-- 4,5 -> 4,3  <-

显然还不够:

update t1 x
   set b = (select min(b) from t1 where b > 1)
;

无论我尝试什么更复杂的东西,例如

UPDATE t1 x
   set (a,b) = (select distinct a,b from (
                    select a, min(b) from t1 where b > 1 group by a)
               )
;

我明白了 SQL-Fehler:ORA-01427:UnterabfragefüreineZeile liefert mehr als eine Zeile 01427. 00000 - “单行子查询返回多行”

这并不令人惊讶,因为我需要为a的每个值添加一行。

当然我可以使用游标循环编写PL / SQL过程但是可以在一个优雅的SQL语句中编写吗?也许使用分区?

1 个答案:

答案 0 :(得分:2)

你的问题有点令人困惑。 您说您希望将值b设置为列a所在的分区b中的最小值,而包含b = 1的行应保持不变。

从我在您的问题中看到的评论(我假设它是您的预期输出),您还希望得到分区内1之后的最小值 - 所以您基本上希望得到最小值b的值大于1

以下是执行此操作的SQL查询

UPDATE t1 alias
  SET b = (
    SELECT min(b) 
    FROM t1 
    WHERE alias.a = t1.a 
      AND t1.b > 1 -- this would get the minimum value higher than 1
    GROUP BY a
  )
  WHERE alias.b > 1 -- update will not affect rows with b <= 1

更新后的输出

 a | b 
---+---
 1 | 0
 1 | 1
 2 | 1
 2 | 2
 3 | 1
 3 | 2
 3 | 2
 4 | 1
 4 | 3
 4 | 3
 4 | 3