我有一张如下图所示的表:
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
具有两种类型的内容,可以通过关键字Good
和Bad
加以区分。我的实际表中还没有RowID
不。在这里,我只使用RowID
来更好地描述我的问题。
对于同一ID
的每组,我想将Label
相关行中的所有Bad
更改为N
(如果有Y
),并将Label
包含col
的至少一行的Good
更改为Y
(如果所有关联的label
为N
)< / p>
对于ID
= 1
(RowID
= 1
到4
)的组,我要{{1}中的Label
} = RowID
改为4
而不是N
,同时更改Y
= Label
或RowID
= { {1}}至2
。
对于RowID
= 3
(Y
= ID
至2
)的组,因为RowID
= 5
已经是8
了,我只想将RowID
= 6
和Y
的{{1}}放到Label
。
对于{{1}的RowID
,7
= 8
(N
= ID
至3
)的组} = {RowID
为9
,而11
= Label
为RowID
。我不需要修改该组。
我当时正在考虑在PL SQL中使用游标,但是它应该效率很低...毕竟我有18亿行...谁能告诉我如何用ORACLE SQL编写此游标?预先谢谢你!
答案 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”在周围移动。