【问题标题】:SQl to Update columns when the fields are nullSQl 在字段为空时更新列
【发布时间】:2014-08-08 14:41:43
【问题描述】:

我有一个 SQL 问题,我对 SQL 比较陌生,所以请不要介意这是否过于幼稚。我正在 ORACLE 中将值从一个表更新到另一个表。

Person

PersonID    BirthPlace
---------------------------
1           Madison,WI,USA        
2            Chicago,IL              
3            Houston,TX,USA            
4            Madison,WI,USA          
5            Madison,WI,USA           
6            Houston,TX,USA            
7            NULL                     

PersonProfile

PersonID  CITY             STATE       COUNTRY
-------------------------------------------------
1         Madison           WI          USA 
2         Chicago           IL          NULL  
3            NULL           NULL        NULL 
4            NULL           WI          NULL 
5            NULL           NULL        USA   
6            HOUSTON        NULL        NULL  
7            NULL           NULL        NULL      

我需要使用来自 Table Person 的值更新 Table Person Profile,并且只需要在 Table Person Profile 中的列具有空值时更新它们,如果两个表都具有空值,那么我需要输入“未知”。

我可以编写单独的更新语句来更新每列中的值,例如更新城市:

Update PersonProfile PF

   SET PF.CITY= (SELECT 
                 CASE
                  WHEN PP.CITY LIKE '%MADISON%'
                        THEN 'MADISON'
                  WHEN PP.CITY LIKE '% Houston%'    
                        THEN 'HOUSTON'
                  WHEN PP.CITY LIKE '% CHICAGO%'    
                        THEN 'CHICAGO'
                  ELSE
                       'UNKNOWN'
                  END AS CITY
                            FROM PERSON PP
                       WHERE PF.PERSONID=PP.PERSON.ID
                       AND   PF.CITY IS NULL)

以及用于更新州和国家/地区的类似查询。

我的问题是,有什么方法可以编写一条更新语句来更新所有三列而不是一一更新?如果我可以在解码函数中使用 like 运算符,而不是使用 CASE 语句?

【问题讨论】:

  • 如果PersonPersonProfile 共享相同的唯一键,为什么它们在不同的表中?
  • 它们在两个独立的数据库中,所以我需要从一个数据库转换到另一个数据库并关闭旧数据库

标签: sql oracle decoding


【解决方案1】:

使用多列更新和正则表达式来解析逗号上的出生地数据。

update PERSONPROFILE pp
set (city, state, country) = (
  select nvl(REGEXP_SUBSTR (BIRTHPLACE, '[^,]+', 1, 1), 'UNKNOWN'), -- city
         nvl(REGEXP_SUBSTR (BIRTHPLACE, '[^,]+', 1, 2), 'UNKNOWN'), -- state
         nvl(REGEXP_SUBSTR (BIRTHPLACE, '[^,]+', 1, 3), 'UNKNOWN')  -- country
  from PERSON p
  where p.id = pp.id);

正则表达式匹配 0 个或多个不匹配逗号的字符、城市的第一次出现、州的第二次出现等。如果出现为 NULL,则将其包装在 NVL 中以设置为“UNKNOWN”。

更新:从那以后,我了解到应该避免使用正则表达式 '[^,]+',因为当列表中有 NULL 元素并且您选择该元素或之后的元素时,它会失败。改用它,因为它允许 NULL:

update PERSONPROFILE pp
set (city, state, country) = (
  select nvl(REGEXP_SUBSTR (BIRTHPLACE, '([^,]*)(,|$)', 1, 1, NULL, 1)), 'UNKNOWN'), -- city
         nvl(REGEXP_SUBSTR (BIRTHPLACE, '([^,]*)(,|$)', 1, 2, NULL, 1)), 'UNKNOWN'), -- state
         nvl(REGEXP_SUBSTR (BIRTHPLACE, '([^,]*)(,|$)', 1, 3, NULL, 1)), 'UNKNOWN')  -- country
  from PERSON p
  where p.id = pp.id);

有关更多信息,请参阅此帖子:Split comma seperated values to columns

【讨论】:

    【解决方案2】:

    是的,要么更新一个像这样的元组:

    set (city, state, country) = (select case when pp.city like ... end as city
                                       , case when ...              end as state
                                       , case ...                   end as country)
    

    我怀疑最好创建一个表函数(我假设它们存在于 Oracle 中),使用 , 作为分隔符将字符串拆分为三列,然后使用合并(假设这个 als 存在于 Oracle 中)进行更新.比如:

    merge into t2
    using t1 (
       select personid, table(split(birthplace))
       from t1
    ) x (PersonID, CITY, STATE, COUNTRY)
        on t2.person_id = x.personid
    when matched 
        set t2.city = case when t2.city is null then x.city else t2.city end
          , t2.state = ...
      , ...
    

    【讨论】:

      【解决方案3】:

      您需要审查您的设计 - 当您处理邮政地址和管理用户输入的值(我假设您正在这样做)时,有几个极端情况。

      这已经在 SO 讨论过:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-11
        • 2010-12-24
        • 1970-01-01
        • 2019-02-20
        • 2018-04-07
        • 1970-01-01
        • 2021-03-05
        • 1970-01-01
        相关资源
        最近更新 更多