2015-06-15 72 views
0

我在oracle 11g上,我被困在这个问题上。根据条件依次更新一列

我的表结构如下

 
╔═══════╦══════╦════════╗ 
║ tm_id ║ flag ║ countr ║ 
╠═══════╬══════╬════════╣ 
║ 1  ║ 0 ║ null ║ 
║ 2  ║ 0 ║ null ║ 
║ 3  ║ 1 ║ null ║ 
║ 4  ║ 0 ║ null ║ 
╚═══════╩══════╩════════╝

我想用一个连续的值,如下

 
╔═══════╦══════╦════════╗ 
║ tm_id ║ flag ║ countr ║ 
╠═══════╬══════╬════════╣ 
║ 1  ║ 0 ║ 1  ║ 
║ 2  ║ 0 ║ 2  ║ 
║ 3  ║ 1 ║ 2  ║ 
║ 4  ║ 0 ║ 3  ║ 
╚═══════╩══════╩════════╝

更新列COUNTR的所有值,所以基本上是COUNTR值只能增加,如果该标志是0.如果它是1那么它不应该增加(或它应该有以前的值)

我试过以下更新语句

UPDATE calendar 
SET countr = case when flag = 0 then tm_id else countr-1 end 

回答

5

SQL Fiddle

的Oracle 11g R2架构设置

CREATE TABLE test (tm_id, flag, countr) AS 
      SELECT 1,0, CAST(NULL AS NUMBER) FROM DUAL 
UNION ALL SELECT 2,0, CAST(NULL AS NUMBER) FROM DUAL 
UNION ALL SELECT 3,1, CAST(NULL AS NUMBER) FROM DUAL 
UNION ALL SELECT 4,0, CAST(NULL AS NUMBER) FROM DUAL 
/

UPDATE test t 
SET countr = (SELECT total 
       FROM (
         SELECT tm_id, 
           SUM(1 - FLAG) OVER (ORDER BY tm_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS total 
         FROM test 
        ) x 
       WHERE t.tm_id = x.tm_id 
      ) 
/

查询1

SELECT * FROM test 

Results

| TM_ID | FLAG | COUNTR | 
|-------|------|--------| 
|  1 | 0 |  1 | 
|  2 | 0 |  2 | 
|  3 | 1 |  2 | 
|  4 | 0 |  3 | 

编辑 - 解释

这里使用的SUM是为analytic function,而不是像通常使用聚合函数。

SUM(1 - FLAG) OVER (ORDER BY tm_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) 

从(几乎)从右至左:

  • ORDER BY tm_id - 为了行按升序tm_id
  • 然后为每一行:
    • 考虑所有的ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW(即只有行从最早的tm_id开始到当前行)
    • 对于那些行,找到SUM(1 - FLAG)(即当标志为零而不是当它为1时递增计数器)。
+0

感谢这工作完美...我尝试了你使用的东西的谷歌搜索,但你能给我一些上下文吗?我很难将它们放在一起,并理解你写的内容。 –

+0

@ user1561770 - 添加了“SUM”分析功能的说明。 – MT0

1

要在update使用子查询:

update calendar t 
    set countr = (select count(*) 
        from calendar t2 
        where t2.tm_id <= t.tm_id and t2.flag = 0 
       ); 

如果你的表是大,你可能会发现,merge更有效。

0

您应该使用光标。 从表中获取所有行。 根据案例条件循环更新一行。 将countr值存储在循环的最后一个声明变量中。 如果flag = 1,则在下一个循环中使用此变量。