使用触发器/过程根据实体的值评估参数

发布于 2024-10-14 13:44:09 字数 2429 浏览 4 评论 0原文

我有以下问题。在我的应用程序中,用户使用特殊系统(力量、感知等,值从 1 到 10)创建一个游戏角色。在保存时或之后(通过调用过程),我需要根据特殊参数值对字符进行统计。我该怎么做?这是关系方案:

在此处输入图像描述

这是 SQL 代码:

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);

以及返回所有参数的查询:

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;

所以最后我希望能够计算每个玩家的携带重量、命中点数和辐射阻力。假设所有公式均为 (player_parameter * 10) + 150。使用什么更好:触发器还是过程?


编辑

我正在尝试使用答案中的代码,但收到错误 遇到符号“INNER”,当期望出现以下其中一项时:( ....

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 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:

enter image description here

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;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

倾听心声的旋律 2024-10-21 13:44:09

我绝对不会使用触发器来做这种事情。听起来您想要一个接受 ID_PLAYER 参数并返回一个值或值记录的函数。像这样的东西(请注意,我不确定我是否理解你所描述的公式,所以我猜测有点

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;

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;
半步萧音过轻尘 2024-10-21 13:44:09

为什么需要两张桌子?我会选择

  • 仅包含所有特殊统计信息的单个表和计算派生统计信息的视图(在您的应用程序中您将查询视图):

    创建视图player_v AS 
    SELECT p.strength, ..., /* 所有属性 */
           p.strength * 10 + 150 作为carry_weight,
           p.endurance * 20 + 150 作为 hit_points,
           (p.endurance - 1) * 2 / 100 作为辐射电阻
      来自玩家 p
    
  • 包含使用触发器更新的派生列的单个表:

    创建或替换触发器player_ins_up_trg 
       更新或插入播放器之前
       对于每一行
    开始
       :new.carry_weight := :new.strength * 10 + 150;
       :new.hit_points := :new.endurance * 20 + 150;
       :new.radiation_resistance := (:new.endurance - 1) * 2 / 100;
    结尾;
    
  • 如果您使用的是 Oracle 11,您还可以使用 虚拟列

    <块引用>

    虚拟列不存储在磁盘上。相反,数据库通过计算一组表达式或函数按需导出虚拟列中的值。

    例如:

    ALTER TABLE 玩家 ADD (carry_weight AS (力量 * 10 + 150));
    

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));
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文