Decode360's Blog

业精于勤而荒于嬉 QQ:150355677 MSN:decode360@hotmail.com

  BlogJava :: 首页 :: 新随笔 :: 联系 ::  :: 管理 ::
  397 随笔 :: 33 文章 :: 29 评论 :: 0 Trackbacks
一段很绕的SQL(双重否定)
 
    前段时间看到一段SQL,感觉实现的逻辑非常绕,而且看了之后想了很久都没有想明白到底是怎么回事,再一直想到我都能记住这段SQL的具体细节了,放到博客上研究一下。以下模拟环境:
 
create table t1 (a int,b int);
insert into t1 values(1,1);
insert into t1 values(1,2);
insert into t1 values(1,3);
insert into t1 values(2,2);
insert into t1 values(2,3);
insert into t1 values(4,1);
insert into t1 values(4,2);
insert into t1 values(4,3);
insert into t1 values(5,1);
insert into t1 values(5,6);
insert into t1 values(6,1);
commit;
 
SQL> select * from t1;
 
    A     B
----- -----
    1     1
    1     2
    1     3
    2     2
    2     3
    4     1
    4     2
    4     3
    5     1
    5     6
    6     1
11 rows selected
 
 
    问题是这样的:t1表中A代表人员编号,B代表事件编号。要求出t1表中所有包含人员2所对应的事件的人员编号。
    它给出的答案是这样的:
 
select distinct a
  from t1 a
where not exists (select 1
          from t1 b
         where a = '2'
           and not exists (select 1
                  from t1 c
                 where c.a = a.a
                   and c.b = b.b));
 
 
    首先可以确定的是结果肯定是正确的。然后来看一下逻辑:这段SQL中用了两层not exists,是用双重否定来取出最终结果的,但是具体的逻辑始终没有看明白,到网上搜索了一下,发现遇到这个问题的人还挺多,找了个比较能够看懂的解答看了下,总算明白了点:
 
http://zhidao.baidu.com/question/47772985.html
 
 
 
 
    关于这道题目可能需要这样来理解:
 
    1、先看最内层
 
    select *
      from t1 b
     where a = '2'
       and not exists (select 1 from t1 c where c.b = b.b)
 
    这个代表人员2对应的事件中,没有任何人对应的集合,很显然是一个空集,因为即便没有任何人对应,也有人员2自己对应。但是如果在c中加一个人员号的限定条件就不一定存在值了。
 
    2、在最内层中加上a限定
 
    select *
      from t1 b
     where a = '2'
       and not exists (select 1
              from t1 c
             where c.a = &a
               and c.b = b.b)

    这就表示人员&a对应的事件中,没有和人员2对应事件相同的事件集合。所以只要在这个查询中没有值的,即表示这个人员对应的事件包含了所有人员2对应的事件。如果有值则表示人员2对应的事件有1件或1件以上是该人员所没有的。
 
    3、最外层就比较明显了
 
    select distinct a
      from t1 a
     where not exists (select 1
              from t1 b
             where a = '2'
               and not exists (select 1
                      from t1 c
                     where c.a = a.a
                       and c.b = b.b))
    用最外层的a.a代替了&a,即把所有人员都进行比对,凡事在下面不存在值的(刚才判断过了,不存在值即包含了2对应的所有事件),即需要获取的人员信息。
   
 
posted on 2009-06-12 21:36 decode360 阅读(2625) 评论(0)  编辑  收藏 所属分类: 05.SQL

只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问