我有一个奇怪的用例。
假设我有一个简单的表Persons
:
USE TestDB
Go
CREATE TABLE Persons (
PersonID int,
LastName varchar(255),
FirstName varchar(255),
City varchar(255)
)
INSERT INTO Persons (PersonID, LastName, FirstName, City)
VALUES
(1, 'Smith', 'John', 'New York'),
(2, 'Doe', 'Jane', 'Los Angeles'),
(3, 'Sixpack', 'Joe', 'Chicago')
我还有一个Overrides
表,用于指定如何更改此表:
CREATE TABLE Overrides (
PersonID int,
ColumnName varchar(255),
OverrideValue varchar(255)
)
INSERT INTO Overrides (PersonID, ColumnName, OverrideValue)
VALUES
(2, 'City', 'CHANGED CITY'),
(1, 'FirstName', 'CHANGED FIRSTNAME'),
(3, 'LastName', 'CHANGED LASTNAME')
PersonID
指定唯一行ColumnName
告诉我该行的哪一列需要修改OverrideValue
告诉我应该在该行中输入什么值我想创建一个将Overrides
表中的替代应用于Persons
表的过程。在上述情况下,Persons
将从其原始状态开始:
PersonID LastName FirstName City
----------- ----------- ----------- -----------
1 Smith John New York
2 Doe Jane Los Angeles
3 Sixpack Joe Chicago
进入以下状态:
PersonID LastName FirstName City
----------- ----------- ----------- -----------
1 Smith CHANGED FIRSTNAME New York
2 Doe Jane CHANGED CITY
3 CHANGED LASTNAME Joe Chicago
我可以根据每行在Overrides
表和UPDATE
上进行非常丑陋的循环,但是我希望找到一种更优雅的方法来解决这种非优雅的情况。
答案 0 :(得分:2)
考虑以下UPDATE ... JOIN ...
语法:
update p
set
p.lastName = case when o.columnName = 'LastName' then o.overrideValue else p.lastName end,
p.firstName = case when o.columnName = 'FirstName' then o.overrideValue else p.firstName end,
p.city = case when o.columnName = 'City' then o.overrideValue else p.city end
from persons p
inner join overrides o on o.personID = p.personID
这是通过将personID
上的两个表联接起来,然后使用case
表达式来更新适当的列而起作用的;对于每个加入的记录,只会发生3个条件分配之一。
PersonID | LastName | FirstName | City -------: | :--------------- | :---------------- | :----------- 1 | Smith | CHANGED FIRSTNAME | New York 2 | Doe | Jane | CHANGED CITY 3 | CHANGED LASTNAME | Joe | Chicago
答案 1 :(得分:1)
这有点复杂。如果您没有太多的列,那么多个left join
可能是最简单的解决方案:
update p
set firstname = coalesce(ofn.overridevalue, p.firstname),
lastname = coalesce(ofn.overridevalue, p.lastname),
city = coalesce(ofn.overridevalue, p.city)
from persons p left join
overrides ofn
on p.personid = ofn.person_id and ofn.columnname = 'firstname' left join
overrides oln
on p.personid = oln.person_id and oln.columnname = 'lastname' left join
overrides oc
on p.personid = c.person_id and oc.columnname = 'city'
where ofn.personid is not null or oln.personid is not null or oc.personid is not null;
如果您有很多列,那么预聚合可能是最好的解决方案:
update p
set firstname = coalesce(ofn.firstname, p.firstname),
lastname = coalesce(ofn.lastname, p.lastname),
city = coalesce(ofn.city, p.city)
from persons p left join
(select o.personid,
max(case when columnname = 'firstname' then overridevalue end) as firstname,
max(case when columnname = 'lastname' then overridevalue end) as lastname,
max(case when columnname = 'city' then overridevalue end) as city
from overrides o
group by o.personid
) o
on o.personid = p.personid;