`

Exists练习查找最小缺失值(Missing Value)

 
阅读更多
第一种方法
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。

 

最后,并不推荐重用返回值并且在多线程运行时也可能得到重复的键


分享到:
评论

相关推荐

    sql exists和not exists用法

    3. **数据完整性检查**:`NOT EXISTS`可以用来检查某些数据是否缺失。 ```sql SELECT * FROM Orders WHERE NOT EXISTS (SELECT 1 FROM Customers WHERE Orders.CustomerID = Customers.CustomerID); ``` #### ...

    EXISTS_和_NOT_EXISTS

    在SQL查询中,`EXISTS` 和 `NOT EXISTS` 子句是两个非常重要的条件运算符,用于在数据检索时筛选满足特定条件的记录。它们主要用于子查询,帮助我们检查主查询的结果集是否存在匹配的子查询结果。让我们深入探讨这两...

    exists 和 not exists的详细解释

    exists 和 not exists的详细解释

    C# word excel ppt 操作详解

    wordDoc.SaveAs(ref path, ref format, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ...

    C#操作word,如何进行查找和替换

    object originalFormat = Missing.Value; // 保持原有格式 object routeDocument = Missing.Value; // 不指定路由文档 doc.SaveAs2(ref fileName, ref originalFormat, ref routeDocument); // 保存文档 app.Quit...

    in和exists的区别

    值得注意的是,如果子查询返回的是一个静态的、已知的值列表,比如`IN (1, 2, 3)`,那么"IN"通常会比"EXISTS"快,因为Oracle可以直接比较这些值。但如果子查询返回的是动态的、未知的值,那么"EXISTS"可能更优。 在...

    exists SQL用法详解、exists和not exists的常用示例

    `EXISTS`和`IN`的区别在于,`IN`通常用于比较单个字段值,而`EXISTS`可以处理更复杂的查询,它关心的是子查询是否返回行,而不关心返回的具体值。`IN`通常用于获取特定值列表内的记录,而`EXISTS`则可以用于检查记录...

    oracle数据库关于exists使用

    - `SELECT * FROM course WHERE NOT EXISTS(...)` 查找所有未被选修的课程。 - 最终的 `SELECT sname FROM student WHERE NOT EXISTS(...)` 找出没有未选课程的学生,即选修了所有课程的学生。 #### 二、Exists 与 ...

    Delphi FileExists检查文件是否存在

    1. **异常处理**:虽然`FileExists`返回一个布尔值,但在进行文件操作时,最好还是包裹在`try-except`块中,以处理可能的异常情况,如权限问题、磁盘满等。 2. **路径规范化**:确保输入的文件路径是绝对路径且正确...

    exists用法说明.doc

    `NOT EXISTS`子句与`EXISTS`相反,它用于查找那些不满足内部查询条件的记录。其基本形式是: ```sql SELECT column1, column2, ... FROM table1 WHERE NOT EXISTS (SELECT 1 FROM table2 WHERE condition) ``` 在...

    in和exists性能解析

    在数据库查询语言中,`IN` 和 `EXISTS` 子句是两种常见的用于关联两个表的方法,它们各自有其独特的性能特点和适用场景。本文将深入解析Oracle中`IN`与`EXISTS`的性能差异,以及如何根据具体需求选择最合适的查询...

    sql in,exists,not in,not exists区别

    SQL 中 IN、EXISTS、NOT IN、NOT EXISTS 的区别 IN、EXISTS、NOT IN、NOT EXISTS 是 SQL 中四种常用的条件判断运算符,它们之间的区别主要体现在使用场景、执行效率和语法结构上。 IN IN 是一种条件判断运算符,...

    57.使用含有关键字exists查找未分配具体部门的员工的所有信息.md

    57.使用含有关键字exists查找未分配具体部门的员工的所有信息.md

    datagridview导入excel

    workbook = app.Workbooks.Open(fileName, missingValue, missingValue, missingValue, missingValue, missingValue, missingValue, missingValue, missingValue, missingValue, missingValue, missingValue, ...

    搞懂mysql的exists

    MySQL中的`EXISTS`子句是SQL查询语句中一种重要的条件判断操作,它用于测试子查询是否返回至少一行数据。在理解`EXISTS`的使用时,我们需要深入探讨其工作原理、优缺点以及与其他查询操作(如`IN`、`JOIN`)的对比。...

    sql server2005 exists使用方法

    ### SQL Server 2005 EXISTS 使用方法详解 #### 一、EXISTS 子句概述 在 SQL Server 2005 中,`EXISTS` 是一个非常实用的子句,用于检查子查询是否返回至少一行数据。如果子查询返回至少一行数据,则 `EXISTS` ...

    经典SQL查询总结关于Exists,not Exists.in ,not in效率的说明。

    **Exists** 和 **Not Exists** 子句通常用于检查子查询是否返回任何行,它们不会返回实际的数据,仅返回一个布尔值。 1. **Exists** - **语法结构**: ```sql SELECT * FROM t1 WHERE EXISTS (SELECT 1 FROM t2...

    oracle中exists_和in的效率问题详解

    Oracle 中 EXISTS 和 IN 的效率问题详解 EXISTS 和 IN 都是 Oracle 中的集合操作符,但它们在使用和执行效率上有所不同。本文将深入探讨 EXISTS 和 IN 的使用场景、执行机制和效率问题。 EXISTS 的使用场景和机制 ...

    sql中exists的用法

    in 操作符用于检测一个值是否在一个列表中,而 exists 用于检测子查询是否返回至少一个记录。 在 SQL 中,in 和 exists 的使用场景可以互换,但是在某些情况下,exists 的效率可能要高于 in。例如: ```sql SELECT ...

    SQL之EXISTS

    exists是用来判断是否存在的,当exists(查询)中的查询存在结果时则返回真,否则返回假。not exists则相反 它所在的查询属于相关子查询,即子查询的查询条件依赖于外层父查询的某个属性值,处理过程一般为: 取外层...

Global site tag (gtag.js) - Google Analytics