SQl 在字段为空时更新列
Posted
技术标签:
【中文标题】SQl 在字段为空时更新列【英文标题】:SQl to Update columns when the fields are null 【发布时间】: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 语句?
【问题讨论】:
如果Person
和PersonProfile
共享相同的唯一键,为什么它们在不同的表中?
它们在两个独立的数据库中,所以我需要从一个数据库转换到另一个数据库并关闭旧数据库
【参考方案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 讨论过:
SQL 数据库设计最佳实践(地址) SQL Database Design Best Practice (Addresses)
如何最好地设计任何 SQL 数据库中的地址位置? How to best design address locations in any SQL Database?
在数据库 (RDBMS) 中存储邮政地址的最佳做法? Best practices for storing postal addresses in a database (RDBMS)?
在 SQL 数据库中存储地址的最佳实践/标准 Best Practice / Standard for storing an Address in a SQL Database
【讨论】:
以上是关于SQl 在字段为空时更新列的主要内容,如果未能解决你的问题,请参考以下文章
sql server 2008环境中,字段为decimal(18,2),当输入为空时,会报错。
解决用 VB 中用 ADO 访问 数据库时 SQL 查询处理 Null 值的问题( 使用 iff(isNull(字段), 为空时的值,不为空时的值) 来处理)