在 Oracle 中触发 - 增加用外键引用的列

     2023-03-27     24

关键词:

【中文标题】在 Oracle 中触发 - 增加用外键引用的列【英文标题】:Trigger in Oracle - increment column referenced with foreign key 【发布时间】:2021-12-04 20:17:31 【问题描述】:

我需要在 Oracle SQL 中创建一个触发器。我有 2 个具有这些属性的实体:

军队

army_name VARCHAR(50) 主键 number_of_soliders 整数

士兵

personal_number 整数主键 solider_name VARCHAR(50) NOT NULL army_name VARCHAR(50) REFERENCES Army(army_name)

现在我需要为 number_of_soliders 创建一个触发器。默认值为 0,每次插入士兵时,我都需要将此值增加 1,对于特定的军队。因此,如果插入一个士兵并引用“美国陆军”,他们的士兵数量会自动增加一。

非常感谢

【问题讨论】:

【参考方案1】:

这是一个特别糟糕的主意,尽管显然很受欢迎。如果您尝试存储可以在运行时计算的内容,那么存储的值不正确只是时间问题。相信我。您根本不应该存储“number_of_soldiers”。你总是可以计算出来的

SQL> show user
USER is "SCOTT"
SQL> -- create the tables
SQL>  CREATE TABLE "SCOTT"."ARMY"
  2     (    "ARMY_NAME" VARCHAR2(20 BYTE) NOT NULL ENABLE,
  3           CONSTRAINT "ARMY_PK" PRIMARY KEY ("ARMY_NAME")
  4    USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
  5    TABLESPACE "USERS"  ENABLE
  6     ) SEGMENT CREATION DEFERRED
  7    PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
  8   NOCOMPRESS LOGGING
  9    TABLESPACE "USERS" ;

Table created.

SQL> --
SQL>  CREATE TABLE "SCOTT"."SOLDIER"
  2     (    "COLUMN1" NUMBER(*,0) NOT NULL ENABLE,
  3          "SOLDIER_NAME" VARCHAR2(20 BYTE) NOT NULL ENABLE,
  4          "ARMY_NAME" VARCHAR2(20 BYTE) NOT NULL ENABLE,
  5           CONSTRAINT "SOLDIER_PK" PRIMARY KEY ("COLUMN1")
  6    USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
  7    TABLESPACE "USERS"  ENABLE,
  8           CONSTRAINT "SOLDIER_FK1" FOREIGN KEY ("ARMY_NAME")
  9            REFERENCES "SCOTT"."ARMY" ("ARMY_NAME") ENABLE
 10     ) SEGMENT CREATION DEFERRED
 11    PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
 12   NOCOMPRESS LOGGING
 13    TABLESPACE "USERS" ;

Table created.

SQL> -- load tables
SQL> -- load tables
SQL> insert into army values ('US ARMY');

1 row created.

SQL> insert into army values ('Canadian Army');

1 row created.

SQL> insert into soldier values (1,'Jody','US ARMY');

1 row created.

SQL> insert into soldier values (2,'Fred','US ARMY');

1 row created.

SQL> insert into soldier values (3,'Bob','US ARMY');

1 row created.

SQL> insert into soldier values (4,'Pierre','Canadian Army');

1 row created.

SQL> insert into soldier values (5,'Rocky','Canadian Army');

1 row created.
SQL> -- Do the query
SQL> select army_name,
  2         count(*)
  3  from soldier
  4  group by army_name
  5  order by army_name;

ARMY_NAME              COUNT(*)
-------------------- ----------
Canadian Army                 2
US ARMY                       3

2 rows selected.

SQL> -- clean up
SQL> drop table  soldier purge;

Table dropped.

SQL> drop table army purge;

Table dropped.

您还有其他几个设计问题,但这只是解决眼前的问题。

【讨论】:

像这样存储冗余数据几乎总是一个坏主意,因为很难完全保证它的正确性。最佳选择:制作视图或物化视图。如果确实需要存储它,最好制作包或程序来管理表中的数据(例如,可以在更新士兵之前始终锁定军队),而不是通过触发器来做到这一点。 15 年来,我管理了一个数据模型,其中包含数百个带有“智能”触发器的表,相信我,它让你大吃一惊。 你说得有道理,但这是学校项目的一部分,我们应该在数据库中而不是视图中有触发器(不要问我为什么) 通常在 education 项目中,您会构建一个 normalized model,而您仅在实践中使用 denormalized 模型,在这种情况下,您认为非常需要它。 @Vaclav 询问你的导师他/她是否可以评论【参考方案2】:

触发器:

SQL> create or replace trigger trg_ai_sol
  2    after insert or delete on soldier
  3    for each row
  4  begin
  5    if inserting then
  6       update army a set
  7         a.number_of_soldiers = a.number_of_soldiers + 1
  8         where a.army_name = :new.army_name;
  9    elsif deleting then
 10       update army a set
 11         a.number_of_soldiers = a.number_of_soldiers - 1
 12         where a.army_name = :old.army_name;
 13    end if;
 14  end;
 15  /

Trigger created.

测试:

SQL> select * From soldier;

no rows selected

SQL> select * from army;

ARMY_NAME    NUMBER_OF_SOLDIERS
------------ ------------------
US Army                       0
Another Army                  0

SQL> insert into soldier values (1, 'Little', 'US Army');

1 row created.

SQL> insert into soldier
  2    select 2, 'Foot', 'Another Army' from dual union all
  3    select 3, 'Oracle', 'US Army' from dual;

2 rows created.

SQL> select * From soldier;

PERSONAL_NUMBER SOLDIER_NAME         ARMY_NAME
--------------- -------------------- --------------------
              1 Little               US Army
              2 Foot                 Another Army
              3 Oracle               US Army

SQL> select * from army;

ARMY_NAME    NUMBER_OF_SOLDIERS
------------ ------------------
US Army                       2
Another Army                  1

SQL> delete from soldier where personal_number in (2, 3);

2 rows deleted.

SQL> select * From soldier;

PERSONAL_NUMBER SOLDIER_NAME         ARMY_NAME
--------------- -------------------- --------------------
              1 Little               US Army

SQL> select * from army;

ARMY_NAME    NUMBER_OF_SOLDIERS
------------ ------------------
US Army                       1
Another Army                  0

SQL>

【讨论】:

非常感谢!按预期工作:) @Vaclav 这会在士兵换军时给出不一致的值。【参考方案3】:

您可以在 Oracle 中创建序列,例如

CREATE SEQUENCE soldier_seq
    MINVALUE 1
    START WITH 1
    INCREMENT BY 1
    CACHE 10;

在表中创建新行时,引用 key0 字段作为序列的增量

insert into soldier
    (personnel_number, soldier_name, army_name)
    values (soldier_seq.nextval, "first and last Name", "USMC")

【讨论】:

序列永远不能保证没有间隙。当“士兵”从“军队”中移除时会发生什么? 问题是如何根据士兵表中的插入(可能还有删除)在陆军级别维护number_of_soldiers 差距不是问题,因为增量是要求。此外,您永远不会删除这样的记录,而是将其标记为已删除(非活动)。计算军队中的士兵人数将包括 where 子句 = active。

用外键 (RI) 替换创建触发器

】用外键(RI)替换创建触发器【英文标题】:ReplaceCreateTriggerwithForeignKey(RI)【发布时间】:2012-01-1609:28:26【问题描述】:创建触发器:SELECT@oldVersionId=(SELECTDISTINCTVERSION_IDFROMDeleted)SELECT@newVersionId=(SELECTDISTINCTVERSION_IDFROMInserted)SELECT@ 查看详情

外键列表及其在 Oracle DB 中引用的表

】外键列表及其在OracleDB中引用的表【英文标题】:ListofforeignkeysandthetablestheyreferenceinOracleDB【发布时间】:2010-12-1608:16:27【问题描述】:我试图找到一个查询,它将返回一个表的外键列表以及它们引用的表和列。我已经完成了一... 查看详情

如何在运行时使用 Oracle 环境中的触发器和/或过程创建外键

】如何在运行时使用Oracle环境中的触发器和/或过程创建外键【英文标题】:howtocreateforeignkeyatruntimeusingTriggersand/orproceduresinOracleenvironment【发布时间】:2016-02-0419:46:54【问题描述】:我有两张表,分别命名为患者和药房。每个患... 查看详情

Spring用外键保存复合主键

】Spring用外键保存复合主键【英文标题】:Springsavecompositeprimarykeywithforeignkeys【发布时间】:2016-04-2714:15:39【问题描述】:我在创建具有复合主键的实体时遇到问题,并且该键也是外键。这是我的表格和关系tablesschematics.当我想... 查看详情

用外键删除其他数据

】用外键删除其他数据【英文标题】:Deleteotherdatawithforeignkey【发布时间】:2019-07-2701:59:09【问题描述】:我正在申请实习。我们在休息时间玩游戏,我正在制作一个应用程序来跟踪比分。我可以与玩家一起添加游戏。之后,我... 查看详情

在mysql中创建两个用外键链接的表,插入、删除和更新

】在mysql中创建两个用外键链接的表,插入、删除和更新【英文标题】:createtwotableslinkedwithforeignkey,insert,delete,andupdateinmysql【发布时间】:2012-12-1409:05:56【问题描述】:我有一个场景,我必须创建一个包含以下字段的表部门名称... 查看详情

完整性约束语法定义

语法说明:[]表示可选,|表示选其中一个外键:参照表的列名,外键中的所有列值在引用的列中必须全部存在,外键可以只引用主键和替代键(unique约束的字段),不能引用被参照表中随机的一组列,被参照表中参照的列的值必须是... 查看详情

AnnotationException:外键引用的列数错误。应该是 2

】AnnotationException:外键引用的列数错误。应该是2【英文标题】:AnnotationException:AForeignkeyreferinghasthewrongnumberofcolumn.shouldbe2【发布时间】:2015-01-2816:53:24【问题描述】:我正在将我的类与我的数据库表进行映射,但是在运行测试... 查看详情

在 Microsoft SQL Server 上插入触发器后 -- 更新新创建记录中的列

】在MicrosoftSQLServer上插入触发器后--更新新创建记录中的列【英文标题】:AfterInsertTriggeronMicrosoftSQLServer--Updatingacolumninanewlycreatedrecord【发布时间】:2018-08-0616:57:00【问题描述】:我有3个表数据表,LookUp_1,LookUp_2都有列id是主键... 查看详情

外键引用oracle中两个表的一个字段

】外键引用oracle中两个表的一个字段【英文标题】:ForeignKeyreferringonefieldoftwotablesinoracle【发布时间】:2013-05-0611:09:44【问题描述】:我正在尝试通过引用不同的表来设置外键。想象一下桌子:Active_Card((主键)Num_id号码,num_card号码... 查看详情

外键(FK_ 必须与引用的主键具有相同的列数

】外键(FK_必须与引用的主键具有相同的列数【英文标题】:Foreignkey(FK_musthavesamenumberofcolumnsasthereferencedprimarykey【发布时间】:2015-09-1822:58:17【问题描述】:我正在使用旧数据库,其中表A由3个复合键组成,表B由2个复合键组成... 查看详情

在休眠 ORM 中使用一个强制外键和一个可选外键中的列

】在休眠ORM中使用一个强制外键和一个可选外键中的列【英文标题】:UsingacolumninonemandatoryandoneoptionalforeignkeyinhibernateORM【发布时间】:2021-10-2109:05:45【问题描述】:我想在一个实体内的一个可选和一个强制复合外键中使用一个... 查看详情

如何在导入过程中禁用oracle约束条件和触发器

参考技术A1、ORACLE数据库中的外键约束名都在表user_constraints中可以查到。其中constraint_type='R'表示是外键约束。2、启用外键约束的命令为:altertabletable_nameenableconstraintconstraint_name3、禁用外键约束的命令为:altertabletable_namedi... 查看详情

sqlserver触发器的问题

SQLServer里面如何实现类似oracle的beforeinsert?比如,我要在B表中插入一条记录,在插入前先检查此记录的name字段,是否存在于A表中的name字段里面,如果存在,则插入,如果不存在,则抛弃这条记录。在oracle里面,可以使用beforein... 查看详情

org.hibernate.MappingException:外键 XXX 的列数必须与引用的主键 YYY 相同

】org.hibernate.MappingException:外键XXX的列数必须与引用的主键YYY相同【英文标题】:org.hibernate.MappingException:ForeignkeyXXXmusthavesamenumberofcolumnsasthereferencedprimarykeyYYY【发布时间】:2013-01-0513:52:41【问题描述】:有如下SQL表:createtableuser... 查看详情

在 Oracle 触发器中动态评估伪记录 (:OLD, :NEW)

】在Oracle触发器中动态评估伪记录(:OLD,:NEW)【英文标题】:DynamicallyEvaluatePseudoRecords(:OLD,:NEW)inOracleTrigger【发布时间】:2015-01-2718:54:03【问题描述】:问题:我有一个客户可以添加列的表格。根据客户的疯狂程度,该表可能包含数... 查看详情

在 oracle 数据库的所有表中更新与特定模式匹配的列

】在oracle数据库的所有表中更新与特定模式匹配的列【英文标题】:Updatingacolumnmatchingaspecificpatterninalltableinanoracledatabase【发布时间】:2014-08-2808:09:13【问题描述】:我需要更新与oracle数据库中所有表中的特定模式匹配的列。例... 查看详情

触发强制外键

】触发强制外键【英文标题】:triggertoforceforeignkey【发布时间】:2013-10-2407:20:40【问题描述】:我有一个表名Service(product,loca,from_agent,to_agent)。product参考Product(pno)from_agent引用Customer(cno)UDriver(drno)UAirline(Ano)to_agent引用Customer(cno)UDriv... 查看详情