Oracle SQL数据修改

时间:2018-07-11 15:54:04

标签: sql oracle

我有一张如下图所示的表:

 RowID |  ID |    col    | Label  |  
-----------------------------------
   1   |  1  |    Bad    |    N   |  
-----------------------------------
   2   |  1  | Very Good |    N   |  <---|
 -----------------------------------
   3   |  1  |Super Good |    N   |  <---| Either Label to be 'Y' (Contain 'Good')
-----------------------------------
   4   |  1  |  Too Bad  |    Y   |  <---$ Need this one to be 'N' (Contain 'Bad')
-----------------------------------
   5   |  2  | F*** Good |    N   | 
-----------------------------------
   6   |  2  | So Good   |    Y   | 
-----------------------------------
   7   |  2  | Really Bad|    Y   |  <---$ Need both to be 'N' (Contain 'Bad')
-----------------------------------
   8   |  2  |    Bad    |    Y   |  <---$ 
-----------------------------------
   9   |  3  |    Good   |    N   | 
-----------------------------------
   10  |  3  |    Good   |    Y   | 
-----------------------------------
   11  |  3  |  Bad Bad  |    N   | 

col具有两种类型的内容,可以通过关键字GoodBad加以区分。我的实际表中还没有RowID 。在这里,我只使用RowID来更好地描述我的问题。

我的目标:

对于同一ID的每组,我想将Label相关行中的所有Bad更改为N(如果有Y ),并将Label包含col的至少一行的Good更改为Y(如果所有关联的labelN)< / p>

例如:

对于ID = 1RowID = 14)的组,我要{{1}中的Label } = RowID改为4而不是N,同时更改Y = LabelRowID = { {1}}至2

对于RowID = 3Y = ID2)的组,因为RowID = 5已经是8了,我只想将RowID = 6Y的{​​{1}}放到Label

对于{{1}的RowID7 = 8N = ID3)的组} = {RowID9,而11 = LabelRowID。我不需要修改该组。

我当时正在考虑在PL SQL中使用游标,但是它应该效率很低...毕竟我有18亿行...谁能告诉我如何用ORACLE SQL编写此游标?预先谢谢你!

1 个答案:

答案 0 :(得分:1)

我认为这可以得到您想要的结果:

select t.*,
  case when col like '%Bad%' then 'N'
       when max(case when col like '%Good%' then label else 'N' end)
         over (partition by id) = 'Y'
       then label
       when row_number()
         over (partition by id, case when col like '%Good%' then 'Y' end order by null) = 1
         then 'Y'
       else label
  end as new_label
from your_table t
order by rn;

        RN         ID COL        LABEL NEW_LABEL
---------- ---------- ---------- ----- ---------
         1          1 Bad        N     N        
         2          1 Very Good  N     Y        
         3          1 Super Good N     N        
         4          1 Too Bad    Y     N        
         5          2 F*** Good  N     N        
         6          2 So Good    Y     Y        
         7          2 Really Bad Y     N        
         8          2 Bad        Y     N        
         9          3 Good       N     N        
        10          3 Good       Y     Y        
        11          3 Bad Bad    N     N        

(我没有使用rn,我只是将其留为用于排序结果集的虚拟列)。

对于任何包含Bad的值,它将选择'N';否则,它是一个好值,并且如果该ID的任何好值已经是Y,则该ID的所有好值的标志将被保留;否则,将半随机的Good值设置为Y。

基于此更新/合并表将很困难,因为至少在您显示的内容上,没有一个键可以与之关联,除非-也许-ID中的值是唯一的。或还有另一个未显示的关键列。


  

我确实有一个唯一的ID列(使用sys_guid())

您可以在合并中使用它,并使第2行和第3行中的哪些变为Y的选择稍微少一些:

merge into your_table target
using (
  select t.*,
    case when col like '%Bad%' then 'N'
         when max(case when col like '%Good%' then label else 'N' end)
           over (partition by id) = 'Y' then label
         when row_number()
           over (partition by id, case when col like '%Good%' then 'Y' end
             order by guid_col) = 1 then 'Y'
         else label
    end as new_label
  from your_table t
) source on (source.guid_col = target.guid_col)
when matched then
  update set target.label = source.new_label
  where target.label is null or target.label != source.new_label
/

4 rows merged.

where子句是为了仅更新标签实际更改的行,而不更新表中的每一行。

此外,如果您需要在修改数据时定期重新计算,则最好使用始终实时计算标签的视图;但是如果不使用此方法,您可能会看到ID中的“ Y”在周围移动。