3

所以在我的数据库中,我有两个具有多对一关系的表。我正在尝试通过查看“子”表上的所有行来更新“父”表(对不起,如果我在这里没有使用正确的术语)并对数据应用不同的规则集以确定要更新的值和。但我想有效地做到这一点(也就是说,快速)。

因此,假设以下表格。

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
)

我使用了简化的示例,需要应用的实际规则比最小/最大/平均要复杂一些。现在,这是我认为可以做到的两种方式。第一个是让过程将父 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;

无论哪种方式,我都觉得我在做额外的工作。第一种方式感觉更糟,因为看起来我做了太多的选择语句(我必须应用的每个规则都有一个,而且有很多)。第二种方式我只需要回到光标的前面而不是再做一次选择,但感觉还是应该有更有效的方式。同时,oracle 有很好的幕后优化,因此任何一种方式都可能被优化为在幕后进行的最佳方式。

所以我的问题是进行这种更新的最快方法是什么,或者我可以不用担心优化它,oracle 会为我处理它吗?

编辑:使示例更复杂一些。

4

3 回答 3

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 中,这通常是一个艰难的计算,由于以下情况,我认为它不适合存储在列中:

  • 三个孩子,每个孩子都有不同的眼睛颜色:要么是无模式,要么是三种模式(每种眼睛颜色一个),这取决于你问谁——有些人会回答“两者”。
  • 三个孩子,两个绿眼睛:好的,这里的模式是绿色,没问题。
  • 四个孩子,两个棕色眼睛,两个蓝色眼睛:棕色和蓝色都是模式。

我希望这有帮助; 可能是您为简化问题所做的努力虽然非常出色,但却让我走上了错误的道路:) 让我知道。

于 2013-05-17T17:45:01.270 回答
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
         )
于 2013-05-17T17:57:22.440 回答
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
)

您的用户定义的聚合函数 ListBloodTypes 和 ComplexCombine 需要定义为:使用用户定义的聚合函数作为指南。

于 2013-05-18T13:40:03.700 回答