关键词:
【中文标题】在 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... 查看详情