所以在我的数据库中,我有两个表有多对一的关系。我试图通过查看'子'表上的所有行来更新'父'表(对不起,如果我没有在这里使用正确的术语)并对数据应用不同的规则集以确定要更新的值用。但我想有效地做到这一点(也就是说,很快)。
因此,请假设以下表格。
PARENT(
ID NUMBER,
NAME VARCHAR(20),
NUMBER_OF_CHILDREN NUMBER,
AVERAGE_CHILD_AGE NUMBER,
OLDEST_CHILD_AGE NUMBER,
YOUNGEST_CHILD_AGE NUMBER,
MODE_EYE_COLOR VARCHAR(20),
EVERY_CHILD_MADE_A VARCHAR(1),
BLOODTYPES_THAT_CAN_BE_ACCEPTED VARCHAR(100),
SOMETHING_COMPLEX COMPLEX_OBJECT_1
)
CHILD(
ID NUMBER,
PARENT_ID NUMBER,
AGE NUMBER,
EYE_COLOR VARCHAR(20),
MADE_AN_A VARCHAR(1),
BLOODTYPE VARCHAR(5),
COMPLEXITY COMPLEX_OBJECT_2
)
我使用了简化示例,需要应用的实际规则比min / max / average更复杂。现在,这些是我认为可以做到的两种方式。第一个是让程序将父ID传递给函数(我使用单独的函数,以便稍后返回并维护此代码更容易)并且每个选择子项然后处理它们。第二种方法是打开一个选择子项的游标,然后将游标传递给每个函数。
PROCEDURE UPDATE_PARENT_1 (PARENT_ID IN NUMBER)
BEGIN
UPDATE PARENT
SET
NUMBER_OF_CHILDREN = CHILD_COUNT_FUNCTION(PARENT_ID),
AVERAGE_CHILD_AGE = CHILD_AGE_AVERAGE_FUNCTION(PARENT_ID),
OLDER_CHILD_AGE = PICK_OLDEST_AGE_FUNCTION(PARENT_ID),
YOUNGEST_CHILD_AGE = PICK_YOUNGEST_AGE_FUNCTION(PARENT_ID),
MODE_EYE_COLOR = MOST_OFTEN_EYE_COLOR_FUNCTION(PARENT_ID),
BLOODTYPES_THAT_CAN_BE_ACCEPTED = DETERMINE_BLOOD_DONOR_TYPES(PARENT_ID),
SOMETHING_COMPLEX = COMPLEX_FUNCTION(PARENT_ID)
WHERE
ID = PARENT_ID;
END;
PROCEDURE UPDATE_PARENT_2 (PARENT_ID IN NUMBER)
CURSOR C IS SELECT * FROM CHILD WHERE CHILD.PARENT_ID = PARENT_ID
BEGIN
OPEN C;
UPDATE PARENT
SET
NUMBER_OF_CHILDREN = CHILD_COUNT_FUNCTION(C),
AVERAGE_CHILD_AGE = CHILD_AGE_AVERAGE_FUNCTION(C),
OLDER_CHILD_AGE = PICK_OLDEST_AGE_FUNCTION(C),
YOUNGEST_CHILD_AGE = PICK_YOUNGEST_AGE_FUNCTION(C),
MODE_EYE_COLOR = MOST_OFTEN_EYE_COLOR_FUNCTION(C)
BLOODTYPES_THAT_CAN_BE_ACCEPTED = DETERMINE_BLOOD_DONOR_TYPES(C),
SOMETHING_COMPLEX = COMPLEX_FUNCTION(C)
WHERE
ID = PARENT_ID;
CLOSE C;
END;
无论哪种方式,我都觉得我正在做额外的工作。第一种方式感觉更糟,因为看起来我做了太多的选择语句(我必须应用每个规则1个,并且有很多)。第二种方式我只需要回到光标的前面,而不是做另一个选择,但它仍然感觉好像应该有一个更有效的方式。同时,oracle具有很好的幕后优化功能,因此无论哪种方式都可以通过优化方式在幕后进行优化。
所以我的问题是进行这种更新的最快方法是什么,或者我可以不担心优化它,oracle会为我处理它吗?
编辑:使示例更复杂。
答案 0 :(得分:3)
你可以做除了眼睛颜色模式之外的所有事情:
UPDATE Parent
SET (Number_Of_Children, Average_Child_Age, Oldest_Child_Age, Youngest_Child_Age) = (
SELECT COUNT(*), AVG(Age), MAX(Age), MIN(Age)
FROM Child
WHERE Parent.ID = Child.Parent_ID
)
我想不出一种适合模式的方法。这在SQL中通常是一个艰难的计算,我认为由于这些情况,它不适合存储在列中:
我希望这会有所帮助;可能是你努力简化这个问题,虽然很好,却让我走错了道路:)让我知道。
答案 1 :(得分:2)
首先,我无耻地借用Ed Gibb的回答。我唯一的补充就是展示如何获得模式。
为此,我使用分析函数而不是聚合。大多数新列都是相同的,只有over (partition by parent_id)
子句。最里面的子查询还包括具有给定眼睛颜色的儿童数量的计数。下一级子查询按该值排序,最外层选择其中一行 - 这将具有模式。
UPDATE Parent
SET (Number_Of_Children, Average_Child_Age, Oldest_Child_Age, Youngest_Child_Age
Mode_Eye_Color) =
(select cnt, avg_age, min_age, max_age, eyecolor
from (select cnt, avg_age, min_age, max_age, eyecolor
ROW_NUMBER() over (order by cnt_ec desc) as seqnum
from (select COUNT(*) over (partition by Parent_id) as cnt,
AVG(Age) over (partition by Parent_id) as avg_age,
MIN(Age) over (partition by Parent_id) as min_age,
MAX(Age) over (partition by Parent_id) as max_age,
COUNT(*) over (partition by Parent_id, eyecolor) as cnt_ec,
eyecolor
from Child
where Parent.ID = Child.Parent_ID
) t
) t
where seqnum = 1
)
答案 2 :(得分:1)
除了更标准的MIN(),MAX()等之外,您还可以使用各种STATS_ *函数。如果这些仍然不够,您可以创建用户定义的聚合函数。 (示例SQL取自另一个答案)
UPDATE Parent
SET (Number_Of_Children, Average_Child_Age, Oldest_Child_Age,
Youngest_Child_Age, MODE_EYE_COLOR, BLOODTYPES_THAT_CAN_BE_ACCEPTED,
SOMETHING_COMPLEX ) =
(
SELECT COUNT(*), AVG(Age), MAX(Age), MIN(Age), STATS_MODE(EYE_COLOR),
ListBloodTypes(BLOODTYPE), ComplexCombine(SOMETHING_COMPLEX)
FROM Child
WHERE Parent.ID = Child.Parent_ID
)
您的用户定义的聚合函数然后需要使用:Using User-Defined Aggregate Functions作为指南来定义ListBloodTypes和ComplexCombine。