在oracle sql中,如何在单行中同时使用新旧值?

在oracle sql中,如何在单行中同时使用新旧值?,sql,oracle,Sql,Oracle,创建表查询 CREATE TABLE ID_TAB ( ID VARCHAR2(20), ID_VALUE VARCHAR2(20), FLAG VARCHAR2(20) ); CREATE TABLE FACT_TABLE ( ID VARCHAR2(20), VALUE VARCHAR2(20), NAME VARCHAR2(100) ); 插入查询 INSERT INTO ID_TAB VALUES('100','ABC','N'); INSER

创建表查询

CREATE TABLE ID_TAB (
    ID VARCHAR2(20),
    ID_VALUE VARCHAR2(20), FLAG VARCHAR2(20)
);

CREATE TABLE FACT_TABLE (
    ID VARCHAR2(20),
    VALUE VARCHAR2(20),
    NAME VARCHAR2(100)
);
插入查询

INSERT INTO ID_TAB VALUES('100','ABC','N');
INSERT INTO ID_TAB VALUES('120','ABC','Y');

INSERT INTO FACT_TABLE VALUES('100','MAX','ORANGE');
我的目标是将事实表“ID”列更新为120,因为它的标志值为“Y”

我原来的表有5000万条记录


我们如何在合并或使用更新中编写查询?

您可以尝试以下方法(尽管我没有尝试):

WHERE EXISTS
确保只更新相应ID_选项卡中的标志设置为“N”的元素。

集合的查询
搜索标志设置为“Y”的对应元素的ID。

要获得性能解决方案(即完全避免连接),您可以切换到动态SQL

我对您的示例进行了一些扩展,以获得更多更新的键,如下所示

请注意,每个
ID\u值
都有一个最大新值,但允许有更多带有
N
标志的旧值,所有这些值都必须更新

INSERT INTO ID_TAB VALUES('100','ABC','N'); -- old key
INSERT INTO ID_TAB VALUES('110','ABC','N'); -- old key
INSERT INTO ID_TAB VALUES('120','ABC','Y'); -- new key
INSERT INTO ID_TAB VALUES('200','EFG','N'); -- old key
INSERT INTO ID_TAB VALUES('210','EFG','N'); -- old key
INSERT INTO ID_TAB VALUES('220','EFG','Y'); -- new key


INSERT INTO FACT_TABLE VALUES('100','MAX','ORANGE');
INSERT INTO FACT_TABLE VALUES('110','MIN','ORANGE');
INSERT INTO FACT_TABLE VALUES('200','MAX','APPLE');
INSERT INTO FACT_TABLE VALUES('210','MIN','APPLE');
INSERT INTO FACT_TABLE VALUES('220','NEW','APPLE');
commit;
UPDATE
语句反映了所有更新选项,例如,键100和110应更改为200

这将导致以下更新

update FACT_TABLE
set ID = case 
when ID in ('100','110') then '200'
when ID in ('200','210') then '220' 
end
where ID in ('100','110','200','210');
请注意,where条件由带标志
N
的所有键组成,并且根据
ID\u值生成
case语句
,将带标志
N
的所有键映射到带标志
Y
的(仅一个)键

这使得UPDATE语句的生成成为表
ID\u选项卡上查询的一项简单的小任务。请参见下面的查询。对于列表创建,使用函数
listag
。主要部分在查询中被注释

with old_keys as (
select  /* get list of all old values */
listagg(''''||ID||'''',',') within  group (order by ID) old_keys
from  ID_TAB where flag = 'N'),
case_stmt as (
select ID_VALUE,
listagg(case when flag = 'N' then ''''||ID||'''' end,',') within  group (order by ID) old_keys,
max(''''||case when flag = 'Y' then ID end||'''')  new_key
from  ID_TAB  
group by ID_VALUE),
case_stmt2 as (
select 
'when ID in ('||OLD_KEYS ||') then ' ||NEW_KEY ||' /* update for '|| ID_VALUE || ' */' case_when, ID_VALUE
from case_stmt),
case_stmt3 as ( /* concatenate CASE WHEN */
select listagg(CASE_WHEN,chr(13)) within  group (order by ID_VALUE) case_when from case_stmt2)
select 
'update FACT_TABLE
set ID = case 
'||
case_when ||
'
end
where ID in ('||
(select old_keys from old_keys)||')' as update_stmt
from case_stmt3
在示例数据上返回此SQL字符串

update FACT_TABLE
set ID = case 
when ID in ('100','110') then '120' /* update for ABC */
when ID in ('200','210') then '220' /* update for EFG */
end
where ID in ('100','110','200','210')

. . 我不完全理解逻辑。Id 120是如何选择的?您需要在这里更清楚地了解您的意图,并在数据之前和之后显示更多的例子。新的值是基于标志的值。如果标志的值是“y”,那么我们将它视为新的值,我们将在事实表中进行更新。基本上,IDGTAB是一个维度表,您可以保证它的存在。对于标志设置为“Y”的特定ID_值,正好有一条记录?多亏了它的工作。由于它将有超过5000万条记录,两次以上加入ID_TAB表将降低性能。我们能在内部做些什么twice@anand19您可以根据维度日期使用专用的
更新
,无需加入-请参阅我的答案。您好,Marmite…在这种情况下,我们不能将日期作为选项
update FACT_TABLE
set ID = case 
when ID in ('100','110') then '120' /* update for ABC */
when ID in ('200','210') then '220' /* update for EFG */
end
where ID in ('100','110','200','210')