我已经制定了一个似乎可行的解决方案,但最好在更复杂的场景中对其进行测试或了解可能涉及哪些类型的场景,例如子子动物或多个动物的子动物亲代动物,或复制的身体部位等。
首先,计算作为动物的一部分的身体部位的百分比和总数,该动物是亲本动物的子动物,并使用新的总数更新回表格。此外,更新父动物以匹配正确的新父动物:
-- update body parts of sub-animals to new value and parent animal
-- also set parent animal bodypartid to itself so it can be identified
with animalbodyparts as (
select * from animals
where bodypartid in (select animalid from animals)
), totals as (
select a.animalid, sum(a.value) as subtotal
from animals a
group by a.animalid
), newtotals as (
select ab.animalid as parentanimalid, t.animalid,
p.bodypartid, p.value / t.subtotal as percentage,
ab.value as newtotal, cast(p.value / t.subtotal * ab.value as integer) as newvalue
from animalbodyparts ab
join totals t on ab.bodypartid = t.animalid
join animals p on t.animalid = p.animalid
)
update a
set
a.animalid =
case
when t.parentanimalid is null then a.animalid
else t.parentanimalid
end,
a.bodypartid =
case
when t.animalid = a.bodypartid then t.parentanimalid
else a.bodypartid
end,
a.value =
case
when t.newvalue is null then a.value
else t.newvalue
end
from animals a
left join newtotals t on a.bodypartid = t.bodypartid
or t.animalid = a.bodypartid;
此外,当 bodypartid 是对作为身体部位的子动物的引用时,我将 bodypartid 更新为与父动物相同。这是因为一旦我更新了子部分的动物 ID,就没有其他方法可以引用曾经引用过动物的身体部位。我将它更新为相同的值,这样我就可以知道需要删除哪些,因为它们现在具有匹配的 bodypartid 和 animalid 值:
--cleanup by removing the body parts that were sub-animals
delete from animals where animalid = bodypartid
演示:http ://www.sqlfiddle.com/#!3/6a5a0/39
注意:我得到了 for 的最终结果,46
因为J
我在总计算之后四舍五入,而您在计算新值之前先四舍五入百分比。如有必要,这应该很容易改变。请注意,无论使用哪种方法,都不能保证新值将与原来的旧总数相加(即 47 + 53 = 100)。有 - 罕见的 - 病理情况(可能涉及子动物的 3 个或更多身体部位),即使您先四舍五入,最终的总数也会与原始情况略有不同。