sql - 如何防止无效数据插入SQL
问题描述
在我的项目中,我需要动态检查条件。要实现这个创建表如下。
CREATE TABLE myconditions
(
conditionid INT IDENTITY PRIMARY KEY CLUSTERED,
minvalue INT,
maxvalue INT,
result INT
)
并包含以下数据,
insert into MyConditions (MinValue, MaxValue, Result)
values (10, 20, 1), (20, 30, 2), (null, 10, 3), (30, null, 3)
我用这个表数据来检查年龄的范围,
declare @age int = 25 --this represents user age
select *
from MyConditions
where @age > isnull(MinValue, @age - 1)
and @age <= isnull(MaxValue, @age)
但现在的问题是,假设如果有人插入了一个无效的范围,比如values (5, 25, 4)
我的意思是这是无效的,因为在数据库中已经有了(10, 20, 1)
这个值。当这@age = 15
两个条件都将通过时。所以我需要防止(5, 25, 4)
这个值添加。如果有人需要添加此(5, 25, 4)
范围,(10, 20, 1)
则应删除此范围值。
我使用 ASP.NET MVC 应用程序将这些数据插入到数据库中。我怎样才能做到这一点?在我的项目中使用的是 Oracle。(在这个问题中我使用了 MS SQL 示例代码,但我需要 oracle)
解决方案
这种数据完整性验证很难以稳健和高性能的方式实现。
对于初学者来说,很大程度上取决于重叠范围的定义。例如,可以说您的所有样本数据范围都是无效的: maxvalue = 10
与 重叠minvalue = 10
,假设边界正在测试>=
并且<=
这是默认值。同样,null
界限会产生复杂性:如果你有一个现有的范围(30, null)
是(40,50)
有效的?
因此,一旦您理清了业务逻辑,接下来就是实施它们的问题。在 Oracle 中,我们可以使用复合触发器来做一些事情。对于每一行,我们将插入/更新行的 ID 存储在一个数组中。然后在语句结束时,我们遍历数组并在交叉连接中查询表以比较日期范围。
create or replace trigger myconditions_trg
for insert or update of minvalue, maxvalue
on myconditions
compound trigger
type condition_array is table of int
index by binary_integer;
conditions condition_array;
procedure validate_range (p_id in int) is
overlapping_range exception;
dummy char(1);
begin
begin
select null into dummy
from myconditions t1
, myconditions t2
where t1.conditionid = p_id
and t2.conditionid != p_id
and t1.minvalue != t2.minvalue
and (
t1.minvalue between t2.minvalue and t2.maxvalue
or
t1.maxvalue between t2.minvalue and t2.maxvalue
)
and rownum = 1;
raise overlapping_range;
exception
when no_data_found then
-- what we're hoping for, no overlaps found
null;
end;
exception
when overlapping_range then
raise_application_error(-20000,
'overlapping range for id #' || p_id);
end validate_range;
procedure validate_ranges is
l_id int;
begin
l_id := conditions.first;
loop
exit when l_id is null;
validate_range (l_id);
l_id := conditions.next(l_id);
end loop;
conditions.delete;
exception
when others then
conditions.delete;
raise;
end validate_ranges;
BEFORE EACH ROW is
begin
-- store id to validate
conditions(:new.conditionid) := 1;
end before each row;
AFTER STATEMENT is
begin
validate_ranges;
end after statement;
end myconditions_trg;
此触发器不会尝试处理多用户场景。老实说,我们无法阻止两个不同的会话创建重叠范围。唯一可以保证的是锁定整个表,但这可能是不可取的。
如果您有兴趣,我在 Oracle LiveSQL 上发布了一个演示(需要免费登录,抱歉!)。在这里找到它。
推荐阅读
- android - 找不到 com.android.tools.build:gradle:4.6
- javascript - 特定端点的Nodejs请求问题(客户端网络套接字断开连接)
- python - Python 3.6 sum() 是否有 `start=0` 关键字参数?
- php - 我已经手动在数据库中插入了记录,但是 sql 查询没有读取 laravel 中的任何数据
- python - 如何将循环字典从 beautifulsoup4 抓取结果保存为 JSON 文件格式..?
- angular - ng2-pdf-viewer 错误:无效的参数对象:需要 .data、.range 或 .url
- java - 如何在 LibGDX-AI >1.8.0 中实现寻路
- mysql - 如何匹配 SQL 中的任何字母?
- python - 试图迭代pymongo中的“子词典”
- python - 使用 Pulp 加速整数线性优化