在oracle中使用默认值替换空值

时间:2015-02-28 13:06:50

标签: plsql

请关注以下oracle初学者的案例:

表" X"包含客户数据:

ID  Variable_A  Variable_B  Variable_C  Variable_D
--------------------------------------------------
1   100         null        abc         2003/07/09
2   null        2           null        null

表"字典"包含我们可以视为客户数据的默认值:

Variable_name  Default_Value
----------------------------
Variable_A     50
Variable_B     0
Variable_C     text
Variable_D     sysdate

目标是检查" X"中的行。通过给定ID并使用" Dictionary"中的默认值替换空值。具体问题是关于最优解决方案,因为现在我自己的解决方案在于使用MERGE INTO语句循环,我认为这不是最优的。当新列被添加到" X"时,有必要使用灵活的代码,而不应该更改它。

2 个答案:

答案 0 :(得分:2)

直接的方法是使用

update X set
  variable_a = coalesce(variable_a, (select default_value from Dictionary where name = 'Variable_A')),
  variable_b = coalesce(variable_b, (select default_value from Dictionary where name = 'Variable_B')),
  ... and so on ...

一般来说它应该足够快。

答案 1 :(得分:1)

由于您不知道表X的哪些字段为空,因此您应该为每一行提供每个默认值。并且由于X的每个字段可能是不同的数据类型,因此Dictionary表应在相应类型的字段中具有每个默认值。这种布局显示在 Fiddle

一个查询,显示X的每一行完全填充了X中的值或其默认值变得相对简单。

select  ID,
        nvl( Var_A, da.Int_Val ) Var_A,
        nvl( Var_B, db.Int_Val ) Var_B,
        nvl( Var_C, dc.Txt_Val ) Var_C,
        nvl( Var_D, dd.Date_Val ) Var_D
from    X
join    Dict  da
    on  da.Name = 'VA'
join    Dict  db
    on  db.Name = 'VB'
join    Dict  dc
    on  dc.Name = 'VC'
join    Dict  dd
    on  dd.Name = 'VD';

将此转换为更新语句稍微复杂一点,但是一旦您使用它几次就很简单:

update  X
    set (Var_A, Var_B, Var_C, Var_D) =(
        select nvl( Var_A, da.Int_Val ),
               nvl( Var_B, db.Int_Val ),
               nvl( Var_C, dc.Txt_Val ),
               nvl( Var_D, dd.Date_Val )
        from    X InnerX
        join    Dict  da
            on  da.Name = 'VA'
        join    Dict  db
            on  db.Name = 'VB'
        join    Dict  dc
            on  dc.Name = 'VC'
        join    Dict  dd 
            on  dd.Name = 'VD'
        where   InnerX.ID = X.ID )
where   exists(
        select  1
        from    X
        where   Var_A is null
            or  Var_B is null
            or  Var_C is null
            or  Var_D is null );

这有一个问题。日期类型的默认值为sysdate,这意味着它将显示填充默认表的日期和时间,而不是执行更新的日期和时间。我想,这不是你想要的。您可以尝试使用动态sql完成所有工作,但这会更复杂。你想在这里做什么太复杂了。

我只看到两个现实选项:要么将有意义的日期存储为默认日期(例如9999-12-31),要么只知道日期类型的每个默认日期都是sysdate并在您的更新。只需更改一行即可在上述更新中完成:

               nvl( Var_D, sysdate )

并摆脱最后一次加入。