开发者

Evaluate parameters based on entity's values using trigger/procedure

I have the following problem. In my application user creates a game character using SPECIAL system (Strength, Perception etc with values from 1 to 10). On saving or after (by calling procedure) i need to count statistics of character on the base of SPECIAL parameters values. How can I do this ? This is the relations scheme:

Evaluate parameters based on entity's values using trigger/procedure

and here's SQL code :

create table Player (
  id_player numeric,
  player_name varchar2(50) not null,
  age decimal not null,
  strength decimal not null,
  perception decimal not null,
  endurance decimal not null,
  charisma decimal not null,
  inteligence decimal not null,
  agility decimal not null,
  luck decimal not null,
  caps decimal not null,
  statistics numeric,
  CONSTRAINT chk_s check (strength <= 10),
  CONSTRAINT chk_p check (perception <= 10),
  CONSTRAINT chk_e check (endurance <= 10),
  CONSTRAINT chk_c check (charisma <= 10),
  CONSTRAINT chk_i check (inteligence <= 10),
  CONSTRAINT chk_a check (agility <= 10),
  CONSTRAINT chk_l check (luck <= 10),
  CONSTRAINT unique_name UNIQUE (player_name),

  CONSTRAINT PLAYER_PK primary key (id_player)
);

create table Player_derived_statistics(
  id_statistics numeric,
  carry_weight decimal,
  hit_points decimal,
  radiation_resistance decimal,

  CONSTRAINT DERIVED_STATISTICS_PK primary key (id_statistics)
);

alter table Player add constraint PLAYER_DERIVED_STATISTICS_FK1 foreign key (statistics) references Player_derived_statistics (id_statistics);

and query returning all parameters:

SELECT p.strength, p.perception, p.endurance, p.charisma, p.inteligence, p.agility, p.luck
from player p inner join player_derived_statistics s on s.id_statistics = p.statistics;

So in the end I'd like to be able to count carry_weight, hit_points and radiation_resistance for each Player. Let's say that all formulas are (player_parameter * 10) + 150. What would be better to use : trigger or procedure ?


EDIT

I'm trying to use the code from开发者_运维百科 answer, but I'm getting error Encountered the symbol "INNER" when expecting one of the following: ( ....

CREATE OR REPLACE PACKAGE pkg_player_stats AS
  FUNCTION get_derived_stats( p_id_player IN player.id_player%TYPE )
    RETURN derived_stats_rec
  IS
    l_stats_rec derived_stats_rec;
  BEGIN
    SELECT (p.strength*10)+150,
           (p.endurance*20)+150,
           ((p.endurance-1)*2)/100
      INTO l_stats_rec.carry_weight,
           l_stats_rec.hit_points,
           l_stats_rec.radiation_resistance
      FROM (
        SELECT p.strength,  
               p.endurance
          from player p inner join player_derived_statistics s on s.id_statistics = p.statistics);
    RETURN l_stats_rec;
  END get_derived_stats;
END;


I definitely wouldn't use a trigger for this sort of thing. It sounds like you would want a function that accepts an ID_PLAYER parameter and returns either a value or a record of values. Something like this (note that I'm not sure that I understand the formulas you're describing so I'm guessing a bit

CREATE OR REPLACE PACKAGE pkg_player_stats
AS
  TYPE derived_stats_rec IS RECORD (
    carry_weight NUMBER,
    hit_points   NUMBER,
    radiation_resistance NUMBER );

  FUNCTION get_derived_stats( p_id_player IN player.id_player%TYPE )
    RETURN derived_stats_rec;
END;

CREATE OR REPLACE PACKAGE pkg_player_stats
AS
  FUNCTION get_derived_stats( p_id_player IN player.id_player%TYPE )
    RETURN derived_stats_rec
  IS
    l_stats_rec derived_stats_rec;
  BEGIN
    SELECT carry_weight         * multiplier + 150,
           hit_points           * multiplier + 150,
           radiation_resistance * multiplier + 150
      INTO l_stats_rec.carry_weight,
           l_stats_rec.hit_points,
           l_stats_rec.radiation_resistance
      FROM (
        SELECT p.strength + 
               p.perception + 
               p.endurance +
               p.charisma + 
               p.inteligence +
               p.agility +
               p.luck multiplier,
               s.carry_weight,
               s.hit_points,
               s.radiation_resistance
          from player p 
               inner join player_derived_statistics s on s.id_statistics = p.statistics);
    RETURN l_stats_rec;
  END get_derived_stats;
END;


Why do you need two tables ? I would go with either

  • A single table with all S.P.E.C.I.A.L stats only and a view that computes the derived statistics (in your application you would query the view):

    CREATE VIEW player_v AS 
    SELECT p.strength, ..., /* all attributes */
           p.strength * 10 + 150 as carry_weight,
           p.endurance * 20 + 150 as hit_points,
           (p.endurance - 1) * 2 / 100 as radiation_resistance
      FROM player p
    
  • A single table with derived columns that you update with a trigger:

    CREATE OR REPLACE TRIGGER player_ins_up_trg 
       BEFORE UPDATE OR INSERT ON player
       FOR EACH ROW
    BEGIN
       :new.carry_weight := :new.strength * 10 + 150;
       :new.hit_points := :new.endurance * 20 + 150;
       :new.radiation_resistance := (:new.endurance - 1) * 2 / 100;
    END;
    
  • If you are using Oracle 11, you could also use a virtual column:

    A virtual column is not stored on disk. Rather, the database derives the values in a virtual column on demand by computing a set of expressions or functions.

    For example:

    ALTER TABLE player ADD (carry_weight AS (strength * 10 + 150));
    
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜