2013-06-20 28 views
3

我有一个表,其中包含,除了其他,这样的领域:id integer, status_id integer, add_date date如何只更新匹配值的一定百分比

我想执行类似这样的查询:

update table set status_id = new_status_id where status_id = old_status_id

而是一个只会更新值的给定的百分比,比如50%。而且,每个日期的更新行的分布应该是相似的;我想更新date = 23.06.2013半行,而不是一半。

回答

6
update table 
set status_id = new_status_id 
where 
    status_id = old_status_id 
    and random() < 0.5 
+0

简单的,但不会考虑日期。它可以更新整个表(如果它足够小) –

+0

@IgorRomanchenko关于日期的不精确更新是可以接受的,并且这个查询是最简单的可能。因此接受。谢谢你的工作,谢谢。 – Dariusz

2

该查询会给你行的id,要更新:

SELECT * 
FROM 
(SELECT id, 
     count(id) OVER (PARTITION BY add_date) cnt, 
     row_num() OVER (PARTITION BY add_date ORDER BY id) rn 
FROM table 
WHERE status_id = old_status_id) sub 
WHERE rn <= cnt * 0.5 -- your percentage 
-- WHERE rn <= cnt * 0.5 + random() -- another (better) version. 
            -- Will update at random if there if only one row 
+1

'ORDER BY id' ..它不在请求中首先更新较小的ID。你可以删除子句以获得任意选择(这会更快,因为两个窗口函数共享相同的窗口),或者用'ORDER BY random()'替换它以获得真正的随机选择。 –

+0

@ErwinBrandstetter是的,我知道。这只是一种习惯,将ORDER BY添加到具有任意列的row_num()中(否则Oracle会抛出错误)。在不需要时使用'random()'不是很好。 (调用'random()'可能不便宜) –

+0

_if它足够小,因为你对我的答案的评论,那么这也不是完美的,因为没有一个只有一行的日期将被删除。还有一个小错误,即count和row_number都返回整数。解决办法就像'rn :: float/cnt' –

0

当躺在床上,并试图睡一个非常简单的解决方案来到我的脑海:

update table 
set status_id = new_status_id 
where 
     status_id = old_status_id 
    and id % 2 = 0; 

由于id实际上是bigserial,所以此查询将与Clodoaldo具有相似的效果。