100分,赚不够另开贴。SQL语句问题

时间:2020-12-10 06:48:06
有t1表,字段name与time为主键,flag取值范围为A,B,C,D之一,class为整数型
name    flag    class     time
--------------------------------------
M1      A        1        2002-08-12
M1      B        2        2002-08-13
N2      A        1        2002-07-14
N2      A        2        2002-07-27
T3      A        4        2002-08-05
T3      B        1        2002-08-09
T3      D        5        2002-08-11
E7      A        1        2002-04-25

按以下要求检索:
对于相同name值,按时间降序排列,逐个判断flag值,如果flag=B且class=1,则符合;
如果flag=A,class=1,且尚未有flag=B的情况出现,则也符合。

也就是说,要找到所有这样的name,在这个name的不同时期,按时间倒推,只对flag值为B或A的第一条记录感兴趣,如果有这样的记录,必须满足class=1,否则日期继续向前追溯,再次遇到flag=A或B,且class=1的记录,一旦满足条件,此name值不再检索。
如上表,检索结果应为:
N2      A        1        2002-07-14
T3      B        1        2002-08-09
E7      A        1        2002-04-25

请众高手不吝赐教!想加分另开贴!

15 个解决方案

#1


select * from t1 a
    where (a.flag=B and a.class= 1)
       or ( a.flag = A 
            and a.class = 1
            and not exists(select * from t1 b
                     where a.name = b.name 
                       and  b.flag = B)
           )
    order by time

#2


下面的这个已经试过了,没有问题。
select * from t1 a
         where  (a.flag='B' and a.class= 1)
         or (a.flag = 'A' 
             and a.class = 1
             and not exists(select * from t1 b
                       where a.name = b.name 
                        and  b.flag = 'B'))
         order by time

#3


不对啊,我只要一条记录,按时间降序的第一条记录,这个我试了,不对

#4


同楼上

#5


刚才没有看清楚,你这里的flag值为B或A的第一条记录感兴趣,好象有歧义,
我是这样理解的如果flag = a ,class=1并且 是第一条记录,如果是flag =b 只要class =1 就可,不管有多少条都选出。
我是这么理解的。

select * from t1 c
       where exists(
                  select name, min(time) from t1 a
                          where (
                                  (a.flag='B' and a.class= 1)
                                   or (a.flag = 'A' 
                                      and a.class = 1
                                      and not exists(select * from t1 b
                                                     where a.name = b.name 
                                                     and  b.flag = 'B'
                                                     )
                                    )
                                  )
                            and a.name =c.name 
                            and a.time =c.time            
                           group by name

         
  )       

#6


通过rain11er(清风) 的代码,你的问题应该解决了吧

#7


这100分该rain11er(清风) 拿了,:)

#8


不是啊,不管是flag=A还是flag=B,都只要第一条记录就行了.也就是说要找这样的每个name:在满足class=1并且flag=A或B的记录中进行筛选,按时间降序排列,如果找到一条flag=B,就是它了,如果flag=A,还要满足它的前一条记录(时间比这条记录稍大的一条)不管class是否=1,flag都不能=B
大哥再想想办法吧.谢谢!

#9


按你的说法, 好像M1  A  1  ...这条记录应该排在最前面也显示出来呀

#10


M1   A    1不显示,因为虽然有class=1 且falg=A的记录,但它的前一条记录flag=B,要找的条件是,要么flag=B,要么flag=A且前一flag<>B

#11


被你说晕了。

给你提个建议:如果你想把这么大的sql防到程序里面,最好不要这样做。程序不是完成任务就可以了,以后要维护的。如果后来的人接你这一块,你让哪个人怎么活
看到一个这么大的语句。上面的语句我昨天晚上写的,今天再看就晕了。
可能我水平很次,不能写出来,不过我认为如果可以写出来的花,这条sql语句肯定不短,不容易理解。
现在不搞pb了,sql水平下降了不少。以前我们一般都是建立几个临时表进行中转,好理解便于维护。你可以采用这个方法。如果你只是想学sql另当别论。

#12


如果真想写出来的话,你最好整理一下你的思路,把他完整,清楚的表述出来,尽管你清楚,但别人不清楚,重新再开一个帖子把。

#13


再帮大家UP一下,:)

#14


select name,flag,class,min(time) from t1 a
         where  (a.flag='B' and a.class= 1)
         or (a.flag = 'A' 
             and a.class = 1
             and not exists(select * from t1 b
                       where a.name = b.name 
                        and  b.flag = 'B'))
         group by name,flag,class

#15


有点头晕,写个procedure吧。

#1


select * from t1 a
    where (a.flag=B and a.class= 1)
       or ( a.flag = A 
            and a.class = 1
            and not exists(select * from t1 b
                     where a.name = b.name 
                       and  b.flag = B)
           )
    order by time

#2


下面的这个已经试过了,没有问题。
select * from t1 a
         where  (a.flag='B' and a.class= 1)
         or (a.flag = 'A' 
             and a.class = 1
             and not exists(select * from t1 b
                       where a.name = b.name 
                        and  b.flag = 'B'))
         order by time

#3


不对啊,我只要一条记录,按时间降序的第一条记录,这个我试了,不对

#4


同楼上

#5


刚才没有看清楚,你这里的flag值为B或A的第一条记录感兴趣,好象有歧义,
我是这样理解的如果flag = a ,class=1并且 是第一条记录,如果是flag =b 只要class =1 就可,不管有多少条都选出。
我是这么理解的。

select * from t1 c
       where exists(
                  select name, min(time) from t1 a
                          where (
                                  (a.flag='B' and a.class= 1)
                                   or (a.flag = 'A' 
                                      and a.class = 1
                                      and not exists(select * from t1 b
                                                     where a.name = b.name 
                                                     and  b.flag = 'B'
                                                     )
                                    )
                                  )
                            and a.name =c.name 
                            and a.time =c.time            
                           group by name

         
  )       

#6


通过rain11er(清风) 的代码,你的问题应该解决了吧

#7


这100分该rain11er(清风) 拿了,:)

#8


不是啊,不管是flag=A还是flag=B,都只要第一条记录就行了.也就是说要找这样的每个name:在满足class=1并且flag=A或B的记录中进行筛选,按时间降序排列,如果找到一条flag=B,就是它了,如果flag=A,还要满足它的前一条记录(时间比这条记录稍大的一条)不管class是否=1,flag都不能=B
大哥再想想办法吧.谢谢!

#9


按你的说法, 好像M1  A  1  ...这条记录应该排在最前面也显示出来呀

#10


M1   A    1不显示,因为虽然有class=1 且falg=A的记录,但它的前一条记录flag=B,要找的条件是,要么flag=B,要么flag=A且前一flag<>B

#11


被你说晕了。

给你提个建议:如果你想把这么大的sql防到程序里面,最好不要这样做。程序不是完成任务就可以了,以后要维护的。如果后来的人接你这一块,你让哪个人怎么活
看到一个这么大的语句。上面的语句我昨天晚上写的,今天再看就晕了。
可能我水平很次,不能写出来,不过我认为如果可以写出来的花,这条sql语句肯定不短,不容易理解。
现在不搞pb了,sql水平下降了不少。以前我们一般都是建立几个临时表进行中转,好理解便于维护。你可以采用这个方法。如果你只是想学sql另当别论。

#12


如果真想写出来的话,你最好整理一下你的思路,把他完整,清楚的表述出来,尽管你清楚,但别人不清楚,重新再开一个帖子把。

#13


再帮大家UP一下,:)

#14


select name,flag,class,min(time) from t1 a
         where  (a.flag='B' and a.class= 1)
         or (a.flag = 'A' 
             and a.class = 1
             and not exists(select * from t1 b
                       where a.name = b.name 
                        and  b.flag = 'B'))
         group by name,flag,class

#15


有点头晕,写个procedure吧。