第一种方法
USE tempdb;
GO
IF OBJECT_ID('dbo.T1') IS NOT NULL
DROP TABLE dbo.T1;
GO
CREATE TABLE dbo.T1
(
keycol INT NOT NULL PRIMARY KEY CHECK(keycol > 0),
datacol VARCHAR(10) NOT NULL
);
-- Minimum missing value query
SELECT MIN(A.keycol) + 1 as missing
FROM dbo.T1 AS A
WHERE NOT EXISTS
(SELECT * FROM dbo.T1 AS B
WHERE B.keycol = A.keycol + 1)
SELECT
CASE
WHEN NOT EXISTS(SELECT * FROM dbo.T1 WHERE keycol = 1) THEN 1
ELSE (SELECT MIN(A.keycol) + 1
FROM dbo.T1 AS A
WHERE NOT EXISTS
(SELECT * FROM dbo.T1 AS B
WHERE B.keycol = A.keycol + 1))
END;
例:重用被删除键值的方法
INSERT INTO dbo.T1(keycol, datacol)
SELECT
CASE
WHEN NOT EXISTS(SELECT * FROM dbo.T1 WHERE keycol = 1) THEN 1
ELSE (SELECT MIN(A.keycol) + 1
FROM dbo.T1 AS A
WHERE NOT EXISTS
(SELECT * FROM dbo.T1 AS B
WHERE B.keycol = A.keycol + 1))
END,
'g';
注:NOT EXISTS谓词只为T1中间断之前的值(在这个例子中是4和7)返回TRUE。如果一个值加上1后不位于同一个表中,那么这人值正好位于一个间断的前面。
-- Populating T1 with more rows
INSERT INTO dbo.T1(keycol, datacol) VALUES(1, 'e'),(2, 'f');
-- Embedding the CASE expression in an INSERT SELECT statement
INSERT INTO dbo.T1(keycol, datacol)
SELECT
CASE
WHEN NOT EXISTS(SELECT * FROM dbo.T1 WHERE keycol = 1) THEN 1
ELSE (SELECT MIN(A.keycol) + 1
FROM dbo.T1 AS A
WHERE NOT EXISTS
(SELECT * FROM dbo.T1 AS B
WHERE B.keycol = A.keycol + 1))
END,
-- Examining the content of T1 after the INSERT
SELECT * FROM dbo.T1;
第二种方法
-- Merging the two cases into one query
SELECT COALESCE(MIN(A.keycol) + 1, 1)
FROM dbo.T1 AS A
WHERE
NOT EXISTS(
SELECT * FROM dbo.T1 AS B
WHERE B.keycol= A.keycol + 1)
AND EXISTS(
SELECT * FROM dbo.T1
WHERE keycol = 1);
GO
见议使用第一种方法:简单、直观、可读性更高
在数据处理时,我们经常会使用一些“自增”的插入方式来处理数据。比如学生学号:B07051001,B07051002....类似的递增关系的数据。
但是,如果中途因为某些原因将其中的一些记录删除掉之后,就会出现断续的记录。这时,我们可能期待将这些中间的缺失值再次利用。以下,就谈谈如何查找最小缺失值。
首先,我们建一个测试表:tb_Test(主键并未设置为自增长):
[c-sharp] view plaincopyprint?
01.create table tb_Test
02.(
03. id int primary key,
04. val char(1) null
05.)
create table tb_Test
(
id int primary key,
val char(1) null
)
插入一些数据:
[c-sharp] view plaincopyprint?
01.insert into tb_Test values(1,'a')
02.insert into tb_Test values(2,'b')
03.insert into tb_Test values(3,'c')
04.insert into tb_Test values(4,'d')
05.insert into tb_Test values(5,'e')
06.insert into tb_Test values(6,'f')
07.insert into tb_Test values(7,'g')
08.insert into tb_Test values(8,'h')
insert into tb_Test values(1,'a')
insert into tb_Test values(2,'b')
insert into tb_Test values(3,'c')
insert into tb_Test values(4,'d')
insert into tb_Test values(5,'e')
insert into tb_Test values(6,'f')
insert into tb_Test values(7,'g')
insert into tb_Test values(8,'h')
删除某些记录,制造“断层”:
delete from tb_Test where id in (1,2,4,5,7);
此时表中数据为不连贯的:
此时能看出最小缺失值应该为:1
我们通过下面这段sql能够得到结果:
select
case
when not exists(select 1 from tb_Test where id=1)
then 1
else (
select min(a.id+1)
from tb_Test as a
where not exists
(
select 1
from tb_Test as b
where b.id=a.id+1
)
)
end as '最小缺失值';
这里使用了一个小的技巧,原理是将表中所有记录的id加1,再与源表中所有记录的id匹配。这样只要有源表中有id缺失,id+1在源表中就会有匹配不到的值。
比如源表中id序列为:1、2、3、5、7(a.id与b.id),则源表中的id+1序列为: 2、3、4、6、8(a.id+1);
这样再代入子查询中,就可以看到a.id+1=4,和a.id+1=6和a.id+1=8在b.id中不存在匹配值。然后再去最小值:min()这样结果就为4。
但是以上上图中的这个序列3,6,8用子查询得出的结果也应该为4,而正确答案为1,显然只是用子查询这样的方式处理是不完整的。
那为什么要把1单独判断呢?这是由1的位置的特殊性决定的。因为1开始时总是处在序列的最前端的位置(正常情况下)。它的前面已经没有数字了,也就是说不存在a.id+1=1(因为我们默认序列是从1开始增长的)。因此没有哪个数字存在与否能判断出1是否存在。所以1需要单独考虑。
处于同样的原理,我们可以用这种方式重用被删除的键:
只要在前面加上:insert into ti_Test(id,val) Select .....(同上)即可。
当然你可以使用coalesce函数来合并,存在1和不存在1的情况:
如下:
select Coalesce(Min(a.id+1),1)
from tb_Test a
where not exists (
select 1
from tb_Test as b
where b.id=a.id+1
) And exists(select 1 from tb_Test where id=1)
注:coalesce函数用于返回第一个非空值。也就是说如果序列中没有1,在被where筛选器筛选后,返回的值为null,此时min(a.id+1)也为null,这样返回的结果就为1。
最后,并不推荐重用返回值并且在多线程运行时也可能得到重复的键
分享到:
相关推荐
exists 和 not exists的详细解释
总结:exists 和not exists语句强调是否返回结果集,不要求知道返回什么,与in的区别就是,in只能返回一个字段值,exists允许返回多个字段 提醒:文章中提供了exists和not exists的常用示例,已经经过本人测试,...
使用EXISTS(或NOT EXISTS)关键字引入一个子查询时,子查询实际上不产生任何数据;它只返回TRUE或FALS值。 指定一个子查询,检测行的存在。 如果子查询包含行,则返回 TRUE IN效率要差(返回子查询)
“exists”和“in”是Oracle中,都是查询某集合的值是否存在在另一个集合,但对不同的数据有不同的用法,主要是在效率问题上存在很大的差别,以下有两个简单例子,以说明 “exists”和“in”的效率问题。
exists是用来判断是否存在的,当exists(查询)中的查询存在结果时则返回真,否则返回假。not exists则相反 它所在的查询属于相关子查询,即子查询的查询条件依赖于外层父查询的某个属性值,处理过程一般为: 取外层...
function_exexists函数详解function_exists函数详解function_exists函数详解function_exists函数详解function_existexists函数详解function_exists函数详解function_exists函数详解function_exists函数详解function_...
使用exists 判断ERP系统中单据分录中物料是否符合某种条件,否则不予保存。
if exists用法,里面包含各种需要用到if exists的情况。
关于Exists,not Exists.in ,not in效率的说明。关于Exists,not Exists.in ,not in效率的说明。关于Exists,not Exists.in ,not in效率的说明。关于Exists,not Exists.in ,not in效率的说明。关于Exists,not Exists.in...
非上传者作品。本人只是学习的时候百度到的比较的文档,拿出来和大家分享一下,希望对大家有所帮助!
在SQL查询语句中,Exists语句的使用方式
基本数据插入 except和intersect和exists和not exists和union和union all sql server
Delphi FileExists检查文件是否存在
oracle in和exists性能解析
里面自己根据网上的资源整理出来的一份sql中in,exists,not in,not exists的使用方法以及注意事项等,有助于初学的朋友们借鉴。
oracle数据库关于exists使用方法与in的比较
exists用法说明.doc
搞懂mysql的exists的使用,搞懂mysql的exists的使用。
详细讲解了exist的使用方法,如何避免使用较为复杂的exists
mysql多表查询和EXISTS查询性能对比