在现有设计下,对业务数据进行查询时可能会碰到关联数据发生变化导致查询结果不一致的情况,例如:
某一商品完成税率调整后,如果相关业务数据没有记录历史数据的税率,就会导致当前查询结果产生的进项税或者销项税税额和调整前查询结果的税额不一致。
这一现象会影响到所有使用外键的情况,大部分情况下对业务影响不大,但涉及税率和考核的情况下就会产生较大影响。特别是在数据库范式设计影响下的数据库设计,影响错综复杂。
为保证数据查询结果不受外键变化的影响,这里提供4种解决方案,具体说明如下:
当数据内容发生变更时,将更新内容以传输链的方式向使用该记录作为外键的记录发出通知信息,要求相关记录进行同步变更(处理完当前时间点的所有后续流程),保证数据的一致性。
使用冗余字段,在数据内容变更可能产生重大影响的情况下,对相关流程数据添加冗余字段,记录业务发生时外键的关键内容。还是以税率为例,在所有涉及结算的数据记录添加税率属性或者税额。
此方法在不改变当前业务架构的情况通过对关键数据表进行调整就可以保证查询结果的一致性,但同样有以下不足:
重新对基础数据进行设计(需要调整主键、索引、触发器、存储过程、相关程序等),保证数据内容发生变更时记录当前数据每次变更时数据的有效时间区间和可用标志。此方法可以避免对业务流程的影响,但是要查询历史数据是需要根据业务发生时间关联外键的时间区间进行查询,影响查询效率。
在数据库设计阶段考虑基础数据内容变化对业务的影响,通过对基础数据变更的控制和增加额外属性(版本号)达到减小消耗和对效率的影响,达到保证查询结果的一致性。该方法仅适用于新设计的系统开发工作。
-- Create table
create table JCXX_YWLB
(
bh NUMBER,
mc VARCHAR2(100),
bz VARCHAR2(500),
bbh NUMBER,
zt NUMBER,
jmsj DATE,
xgsj DATE
)
tablespace USERS
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
next 1M
minextents 1
maxextents unlimited
);
-- Add comments to the table
comment on table JCXX_YWLB
is '基础信息-业务类别';
-- Add comments to the columns
comment on column JCXX_YWLB.bh
is '编号';
comment on column JCXX_YWLB.mc
is '名称';
comment on column JCXX_YWLB.bz
is '备注';
comment on column JCXX_YWLB.bbh
is '版本号';
comment on column JCXX_YWLB.zt
is '状态';
comment on column JCXX_YWLB.jmsj
is '建目时间';
comment on column JCXX_YWLB.xgsj
is '修改时间';
-- Create/Recreate primary, unique and foreign key constraints
alter table JCXX_YWLB
add constraint UKEY_YWLB_BHBBH unique (BH, BBH)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
next 1M
minextents 1
maxextents unlimited
);
alter table JCXX_YWLB
add constraint UKEY_YWLB_MCBBH unique (MC, BBH)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
next 1M
minextents 1
maxextents unlimited
);
-- 业务类别:商品所属业务类别,如:教材教辅、一般图书、非图业务、文创业务
-- 2023年11月28日
-- 一起种梧桐吧
Procedure p001_ywlb(in_type In Varchar2,
in_bh In Number,
in_mc In Varchar2,
in_bz In Varchar2,
out_code Out Number,
out_text Out Varchar2) Is
v_bh Number;
v_bbh Number;
Begin
out_code := 0;
Case
-- 根据 in_type类型选择不同的执行分支
-- A=新增、U=更新、D=逻辑删除
When upper(Trim(in_type)) = 'A' Then
-- 新增:业务类别名称不能为空
If pk00_comm.f001_isnotnull(in_mc) = False Then
out_code := -1;
out_text := '名称不能为空值';
Return;
End If;
Select nvl(Max(bh), 0) + 1 Into v_bh From jcxx_ywlb;
Insert Into jcxx_ywlb
(bh, mc, bz, bbh, zt, jmsj, xgsj)
Values
(v_bh, in_mc, in_bz, 1, 1, Sysdate, Null);
out_text := '业务类别添加成功';
Commit;
When upper(Trim(in_type)) = 'U' Then
-- 更新:业务类别编号、名称不能为空
If pk00_comm.f001_isnotnull(in_bh) = False Then
out_code := -1;
out_text := '编号不能为空值';
Return;
Elsif pk00_comm.f001_isnotnull(in_mc) = False Then
out_code := -1;
out_text := '名称不能为空值';
Return;
End If;
Select nvl(Max(bbh), 0) + 1
Into v_bbh
From jcxx_ywlb
Where bh = in_bh;
Update jcxx_ywlb
Set zt = 0, xgsj = Sysdate
Where bh = in_bh
And zt = 1;
Insert Into jcxx_ywlb
(bh, mc, bz, bbh, zt, jmsj, xgsj)
Values
(in_bh, in_mc, in_bz, v_bbh, 1, Sysdate, Null);
out_text := '业务类别更新成功';
Commit;
When upper(Trim(in_type)) = 'D' Then
-- 逻辑删除:业务类别编号不能为空
If pk00_comm.f001_isnotnull(in_bh) = False Then
out_code := -1;
out_text := '编号不能为空值';
Return;
End If;
Update jcxx_ywlb
Set zt = 0, xgsj = Sysdate
Where bh = in_bh
And zt = 1;
out_text := '业务类别停用成功';
Commit;
Else
out_code := -1;
out_text := '未知指令类型';
End Case;
Exception
When Others Then
out_code := Sqlcode;
out_text := Sqlerrm;
Rollback;
End p001_ywlb;
-- Create table
create table JCXX_SPFL_CW
(
bh NUMBER,
mc VARCHAR2(100),
bz VARCHAR2(500),
bbh NUMBER,
zt NUMBER,
ywlb_bh NUMBER,
ywlb_bbh NUMBER,
jmsj DATE,
xgsj DATE
)
tablespace USERS
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
next 1M
minextents 1
maxextents unlimited
);
-- Add comments to the table
comment on table JCXX_SPFL_CW
is '基础信息-商品分类-财务分类';
-- Create/Recreate primary, unique and foreign key constraints
alter table JCXX_SPFL_CW
add constraint UKEY_SPFL_CW_BHBBH unique (BH, BBH)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
next 1M
minextents 1
maxextents unlimited
);
alter table JCXX_SPFL_CW
add constraint UKEY_SPFL_CW_MCBBH unique (MC, BBH)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
next 1M
minextents 1
maxextents unlimited
);
-- 财务分类:
-- 2023年11月28日
-- 一起种梧桐吧
Procedure p002_spfl_cw(in_type In Varchar2,
in_bh In Number,
in_mc In Varchar2,
in_bz In Varchar2,
in_ywlb_bh In Number,
in_ywlb_bbh In Number,
out_code Out Number,
out_text Out Varchar2) Is
v_bh Number;
v_bbh Number;
Begin
out_code := 0;
Case
-- 根据 in_type类型选择不同的执行分支
-- A=新增、U=更新、D=逻辑删除
When upper(Trim(in_type)) = 'A' Then
-- 新增:业务分类名称不能为空、上级分类编号和版本号不能为空
If pk00_comm.f001_isnotnull(in_mc) = False Then
out_code := -1;
out_text := '名称不能为空值';
Return;
End If;
If pk00_comm.f001_isnotnull(in_ywlb_bh) = False Then
out_code := -1;
out_text := '业务类别编号不能为空值';
Return;
End If;
If pk00_comm.f001_isnotnull(in_ywlb_bbh) = False Then
out_code := -1;
out_text := '业务类别版本号不能为空值';
Return;
End If;
Select nvl(Max(bh), 0) + 1 Into v_bh From jcxx_spfl_cw;
Insert Into jcxx_spfl_cw
(bh, mc, bz, bbh, zt, ywlb_bh, ywlb_bbh, jmsj, xgsj)
Values
(v_bh,
in_mc,
in_bz,
1,
1,
in_ywlb_bh,
in_ywlb_bbh,
Sysdate,
Null);
out_text := '财务分类添加成功';
Commit;
When upper(Trim(in_type)) = 'U' Then
-- 更新:业务类别编号、名称不能为空
If pk00_comm.f001_isnotnull(in_bh) = False Then
out_code := -1;
out_text := '编号不能为空值';
Return;
Elsif pk00_comm.f001_isnotnull(in_mc) = False Then
out_code := -1;
out_text := '名称不能为空值';
Return;
End If;
If pk00_comm.f001_isnotnull(in_ywlb_bh) = False Then
out_code := -1;
out_text := '业务类别编号不能为空值';
Return;
End If;
If pk00_comm.f001_isnotnull(in_ywlb_bbh) = False Then
out_code := -1;
out_text := '业务类别版本号不能为空值';
Return;
End If;
Select nvl(Max(bbh), 0) + 1
Into v_bbh
From jcxx_spfl_cw
Where bh = in_bh;
Update jcxx_spfl_cw
Set zt = 0, xgsj = Sysdate
Where bh = in_bh
And zt = 1;
Insert Into jcxx_spfl_cw
(bh, mc, bz, bbh, zt, ywlb_bh, ywlb_bbh, jmsj, xgsj)
Values
(in_bh,
in_mc,
in_bz,
v_bbh,
1,
in_ywlb_bh,
in_ywlb_bbh,
Sysdate,
Null);
out_text := '业务分类更新成功';
Commit;
When upper(Trim(in_type)) = 'D' Then
-- 逻辑删除:业务分类编号不能为空
If pk00_comm.f001_isnotnull(in_bh) = False Then
out_code := -1;
out_text := '编号不能为空值';
Return;
End If;
Update jcxx_spfl_cw
Set zt = 0, xgsj = Sysdate
Where bh = in_bh
And zt = 1;
out_text := '财务分类停用成功';
Commit;
Else
out_code := -1;
out_text := '未知指令类型';
End Case;
Exception
When Others Then
out_code := Sqlcode;
out_text := Sqlerrm;
Rollback;
End p002_spfl_cw;