先看表里的测试数据:
NAME DT VAL
A 2008-06-17 10
A 2008-06-16 09
A 2008-06-15 08
A 2008-06-14 06
A 2008-06-13 -1
A 2008-06-12 07
A 2008-06-11 13
B 2008-06-17 10
B 2008-06-16 09
B 2008-06-15 0
B 2008-06-14 02
B 2008-06-13 -1
B 2008-06-12 07
B 2008-06-11 10
C 2008-06-17 0
C 2008-06-16 09
C 2008-06-15 0
C 2008-06-14 06
C 2008-06-13 225
C 2008-06-12 150
C 2008-06-11 100可能要求进行的查询和期望得到的结果如下:
1.查询在连续N天里val值大于M的员工及其相应的记录
如要求查询连续4天val值大于05则应该返回:
A 2008-06-17 10
A 2008-06-16 09
A 2008-06-15 08
A 2008-06-14 06
C 2008-06-14 06
C 2008-06-13 165
C 2008-06-12 150
C 2008-06-11 100
或各组答案中最接近今天的那条记录:
A 2008-06-17 10
C 2008-06-14 062.查询在连续N天里val值每天递增M的员工及其相应的记录
如要求查询连续3天里val值每天增加1的员工则应该返回:
A 2008-06-17 10
A 2008-06-16 09
A 2008-06-15 08
或各组答案中最接近今天的那条记录:
A 2008-06-17 103.查询在连续N天里val值每天递增M%的员工及其相应的记录
如要求查询连续3天里val值每天增加50%的员工则应该返回:
C 2008-06-13 225
C 2008-06-12 150
C 2008-06-11 100
或各组答案中最接近今天的那条记录:
C 2008-06-13 225这种类型的查询是否能只用数据库查询语句解决而不需借助其它编程语言编程进行分析?如果可以的话,又能不能不使用存储过程来完成?因为可能不单用在sqlserver里,还要用在access里。但我自己也觉得不用存储过程来完成的希望不大。希望各位踊跃发表意见。

解决方案 »

  1.   

    蛤要能获得数据,用什么编程语言来进行处理都可行的.数据库的强项是存储数据,算法并不是SQL的特长.比如,把这些数据转存到数组里,用别的算法语言来处理类似你说的这些问题,个人感觉要比弄一大堆@变量方便得多.
      

  2.   

    翻老古董,
    LZ看看这两个帖子,
    希望有所启发,
    睡觉了~
    http://topic.csdn.net/t/20050110/14/3713252.html http://topic.csdn.net/u/20070615/12/9b7c5e69-7db6-47b4-8a36-72d1694a7ef1.html
      

  3.   

    1.查询在连续N天里val值大于M的员工及其相应的记录 
    如要求查询连续4天val值大于05则应该返回: 
    A 2008-06-17 10 
    A 2008-06-16 09 
    A 2008-06-15 08 
    A 2008-06-14 06 
    C 2008-06-14 06 
    C 2008-06-13 165 
    C 2008-06-12 150 
    C 2008-06-11 100 
    select *
    from 表 t,(
    select a.name,a.dt as bdt,d.dt as edt
    from 表 a inner join 表 b on a.name=b.name and a.dt=b.dt-1 
        inner join 表 c on a.name=c.name and b.dt=c.dt-1
        inner join 表 d on a.name=d.name and c.dt=d.dt-1
    where a.val>5 and b.val>5 and c.val>5 and d.val>5
    ) s
    where t.name=s.name and t.dt between s.bdt and s.edt.
        [align=center]====  ====
    [/align]
    .
    贴子分数<20:对自已的问题不予重视。
    贴子大量未结:对别人的回答不予尊重。
    .
      

  4.   

    或各组答案中最接近今天的那条记录: 
    A 2008-06-17 10 
    C 2008-06-14 06 
    select a.*
    from 表 a inner join 表 b on a.name=b.name and a.dt=b.dt-1 
        inner join 表 c on a.name=c.name and b.dt=c.dt-1
        inner join 表 d on a.name=d.name and c.dt=d.dt-1
    where a.val>5 and b.val>5 and c.val>5 and d.val>5.
        [align=center]====  ====
    [/align]
    .
    贴子分数<20:对自已的问题不予重视。
    贴子大量未结:对别人的回答不予尊重。
    .
      

  5.   

    2.查询在连续N天里val值每天递增M的员工及其相应的记录 
    如要求查询连续3天里val值每天增加1的员工则应该返回: 
    A 2008-06-17 10 
    A 2008-06-16 09 
    A 2008-06-15 08 
    或各组答案中最接近今天的那条记录: 
    A 2008-06-17 10 
    select a.*
    from 表 a inner join 表 b on a.name=b.name and a.dt=b.dt-1 
        inner join 表 c on a.name=c.name and b.dt=c.dt-1
        inner join 表 d on a.name=d.name and c.dt=d.dt-1
    where a.val=b.val+1 
        and b.val>=c.val+1
        and c.val>=d.val+1
    .
        [align=center]====  ====
    [/align]
    .
    贴子分数<20:对自已的问题不予重视。
    贴子大量未结:对别人的回答不予尊重。
    .
      

  6.   

    DECLARE @t TABLE(NAME VARCHAR, DT DATETIME, VAL INT)
    INSERT @t SELECT 'A', '2008-06-17', 10 
    UNION ALL SELECT 'A', '2008-06-16', 09 
    UNION ALL SELECT 'A', '2008-06-15', 08 
    UNION ALL SELECT 'A', '2008-06-14', 06 
    UNION ALL SELECT 'A', '2008-06-13', -1 
    UNION ALL SELECT 'A', '2008-06-12', 07 
    UNION ALL SELECT 'A', '2008-06-11', 13 
    UNION ALL SELECT 'B', '2008-06-17', 10 
    UNION ALL SELECT 'B', '2008-06-16', 09 
    UNION ALL SELECT 'B', '2008-06-15', 0 
    UNION ALL SELECT 'B', '2008-06-14', 02 
    UNION ALL SELECT 'B', '2008-06-13', -1 
    UNION ALL SELECT 'B', '2008-06-12', 07 
    UNION ALL SELECT 'B', '2008-06-11', 10 
    UNION ALL SELECT 'C', '2008-06-17', 0 
    UNION ALL SELECT 'C', '2008-06-16', 09 
    UNION ALL SELECT 'C', '2008-06-15', 0 
    UNION ALL SELECT 'C', '2008-06-14', 06 
    UNION ALL SELECT 'C', '2008-06-13', 225 
    UNION ALL SELECT 'C', '2008-06-12', 150 
    UNION ALL SELECT 'C', '2008-06-11', 100 
    --连续4天val都大于5的
    DECLARE @d INT,@val INT
    SELECT @d=4,@val=5SELECT * FROM @t a WHERE EXISTS(SELECT 1 FROM @t b WHERE DATEDIFF(dd,a.dt,dt) BETWEEN 0 AND @d-1 AND val>@val AND name=a.Name
    AND NOT EXISTS(SELECT 1 FROM @t WHERE dt BETWEEN a.dt AND DATEADD(dd,@d-1,a.dt) AND Name=a.Name AND val<=@val)
    GROUP BY Name HAVING COUNT(*)>=@d)
    /*
    A 2008-06-14 00:00:00.000 6
    C 2008-06-11 00:00:00.000 100
    即,得到这两条记录为对应的Name里起始日期,那连以它们为初始,连续的@d天内,val都是大于@val的
    如果原始记录还有一条 A 2008-06-18 20 这样的记录,那么, A的6-15也会被选出,即一共有5天是连续的。也就是说从6-14起始是满足的(到6-17),从6-15也是满足的(到6-18)
    取到初始值,怎么得到你要求的结果,这已经不重要了。
    或者说,你要求的是最近的那一条,我给出的是最远的那一条,本质一样,反着写一下就可以了。
    */--连续3天每天递增1的
    SELECT @d=3,@val=1
    SELECT * FROM @t a WHERE EXISTS(SELECT 1 FROM @t WHERE DATEDIFF(dd,a.dt,dt) BETWEEN 0 AND @d-1 AND name=a.Name 
    AND NOT EXISTS(SELECT 1 FROM @t b WHERE dt BETWEEN DATEADD(dd,1,a.dt) AND DATEADD(dd,@d-1,a.dt) AND name=a.Name
    AND EXISTS(SELECT 1 FROM @t WHERE name=b.name AND DATEDIFF(dd,dt,b.dt)=1 AND b.val-val!=@val)
    )
    GROUP BY Name HAVING MAX(val)-MIN(val)=(@d-1)*@val)
    /*
    A 2008-06-15 00:00:00.000 8
    结果意义同第一个
    */第三个就不写了,跟第二天比,改改过节滤条件里的算述运算就可以了,换汤不换药
    乱写的,不保证正确。
      

  7.   

    关于写多个join的朋友,如果楼主的要求是连续20天,那是否写20个join呢?呵呵。
      

  8.   

    SELECT * FROM @t a WHERE EXISTS(SELECT 1 FROM @t b WHERE DATEDIFF(dd,a.dt,dt) BETWEEN 0 AND @d-1 AND val>@val AND name=a.Name)GROUP BY Name HAVING COUNT(*)>=@d)
    fc大师,这条语句不行吗?为什么还要再加上AND NOT EXISTS(SELECT 1 FROM @t WHERE dt BETWEEN a.dt AND DATEADD(dd,@d-1,a.dt) AND Name=a.Name AND val<=@val)
    条件呢?谢谢了.
      

  9.   

    哦,又仔细地看一看,明白了,第一从句是只要在相隔天数内有>val的就记录下来,但可能相隔m(m<@d)天的正好不符合,然后再加上后一句
    刚开始我是想错了,我起初认为第一条从句就是管连续的了,现在想想那只是个符合条件从句
    谢谢您,呵呵。
      

  10.   

    对不起,这几天很忙,今天才能喘口气,一上来就看到有好消息
    fcuandy兄的语句很好,我稍微修改了一下就可以直接用到access中去,真是非常感谢。
    贪心点再问多一下,希望让大家也一起受益:
    在fcuandy兄上面那两个查询语句里,的确是可以完成我帖子里提出的问题,但我觉得有点取巧(主要体现在having部分,的确用得很妙),不太适合普遍情况的扩展,例如:
    1.针对第一条语句,如果我的要求是在连续4天内其中有2天val值超过5的,那应该怎么改?我试过改COUNT(*)>=@d的值,但还是得不到正确的结果。。
    2.针对第二条语句,如果我的要求是连续3天都在增加,但增加多少不管又应该怎么改?我试过修改b.val-val!=@val部分和删除HAVING MAX(val)-MIN(val)=(@d-1)*@val),但没有得出正确结果。
    如果解决这两个问题(能不join就不join吧),我另外开帖给分吧。。可惜我在这个版发贴最多只能给100分。
      

  11.   

    你的这个问题,其实以前有人问过。
    我也写过,写法跟6楼贴的子陌老大的思路差不多。
    因为这贴6楼已贴了这种写法,所以我换了个写法来写而已。至于你后面提的,我个人理解的是 比如:2008-1-1
    2008-1-2
    2008-1-3
    2008-1-4
    2008-1-5这5个日期。 4(@d)天之内有2个val(@v)超过5,  @d>@v. 反之,@d<@v的话,则不可能。也就是说,从这里分析, @v个日期间val满足条件的起止时间跨度不超过@d.
    那么其实写法就更简单了。连续N天,并不是取巧的写法,而是比这个要求更高的写法。DECLARE @t TABLE(NAME VARCHAR, DT DATETIME, VAL INT)
    INSERT @t SELECT 'A', '2008-06-17', 10 
    UNION ALL SELECT 'A', '2008-06-16', 09 
    UNION ALL SELECT 'A', '2008-06-15', 08 
    UNION ALL SELECT 'A', '2008-06-14', 06 
    UNION ALL SELECT 'A', '2008-06-13', -1 
    UNION ALL SELECT 'A', '2008-06-12', 07 
    UNION ALL SELECT 'A', '2008-06-11', 13 
    UNION ALL SELECT 'B', '2008-06-17', 10 
    UNION ALL SELECT 'B', '2008-06-16', 09 
    UNION ALL SELECT 'B', '2008-06-15', 0 
    UNION ALL SELECT 'B', '2008-06-14', 02 
    UNION ALL SELECT 'B', '2008-06-13', -1 
    UNION ALL SELECT 'B', '2008-06-12', 07 
    UNION ALL SELECT 'B', '2008-06-11', 10 
    UNION ALL SELECT 'C', '2008-06-17', 0 
    UNION ALL SELECT 'C', '2008-06-16', 09 
    UNION ALL SELECT 'C', '2008-06-15', 0 
    UNION ALL SELECT 'C', '2008-06-14', 06 
    UNION ALL SELECT 'C', '2008-06-13', 225 
    UNION ALL SELECT 'C', '2008-06-12', 150 
    UNION ALL SELECT 'C', '2008-06-11', 100 
    --连续4天内有2次val都大于5的
    DECLARE @d INT,@val INT,@v INT
    SELECT @d=4,@val=5,@v=2
    --鉴于中间满足条件的日期不是连续的,所以我多连了一次表,列出了符合条件的组合。 实际上,在上贴的回贴中得到的也是类似于子查询这一部分,要得到组合同样的多一次连表即可
    SELECT x.Name Name,x.dt GroupStart,y.dt CurrentDateInGroup,y.val CurrentVal
    FROM 
    (SELECT * FROM @t a WHERE (SELECT COUNT(*) FROM @t WHERE a.name=name AND dt BETWEEN a.dt AND DATEADD(dd,@d-1,a.dt) AND val>@val)>=@v) x
    INNER JOIN @t y
    ON x.name=y.name AND y.dt BETWEEN x.dt AND DATEADD(dd,@d-1,x.dt) AND y.val>@val--至于第二个问题,你所谓的增加,是基于始起日期增加,还是递增(而不管增量是否相同)
      

  12.   

    DECLARE @t TABLE(NAME VARCHAR, DT DATETIME, VAL INT)
    INSERT @t SELECT 'A', '2008-06-17', 10 
    UNION ALL SELECT 'A', '2008-06-16', 09 
    UNION ALL SELECT 'A', '2008-06-15', 08 
    UNION ALL SELECT 'A', '2008-06-14', 06 
    UNION ALL SELECT 'A', '2008-06-13', -1 
    UNION ALL SELECT 'A', '2008-06-12', 07 
    UNION ALL SELECT 'A', '2008-06-11', 13 
    UNION ALL SELECT 'B', '2008-06-17', 10 
    UNION ALL SELECT 'B', '2008-06-16', 09 
    UNION ALL SELECT 'B', '2008-06-15', 0 
    UNION ALL SELECT 'B', '2008-06-14', 02 
    UNION ALL SELECT 'B', '2008-06-13', -1 
    UNION ALL SELECT 'B', '2008-06-12', 07 
    UNION ALL SELECT 'B', '2008-06-11', 10 
    UNION ALL SELECT 'C', '2008-06-17', 0 
    UNION ALL SELECT 'C', '2008-06-16', 09 
    UNION ALL SELECT 'C', '2008-06-15', 0 
    UNION ALL SELECT 'C', '2008-06-14', 06 
    UNION ALL SELECT 'C', '2008-06-13', 225 
    UNION ALL SELECT 'C', '2008-06-12', 150 
    UNION ALL SELECT 'C', '2008-06-11', 100 SELECT * FROM @t ORDER BY Name,dt
    --连续4天递增的
    DECLARE @d INT
    SELECT @d=4SELECT * FROM @t a WHERE EXISTS(SELECT 1 FROM @t WHERE DATEDIFF(dd,a.dt,dt) BETWEEN 0 AND @d-1 AND name=a.Name 
                        AND NOT EXISTS(SELECT 1 FROM @t b WHERE dt BETWEEN DATEADD(dd,1,a.dt) AND DATEADD(dd,@d-1,a.dt) AND name=a.Name
                                    AND EXISTS(SELECT 1 FROM @t WHERE name=b.name AND DATEDIFF(dd,dt,b.dt)=1 AND b.val-val<=0)
                                )
                        GROUP BY Name HAVING COUNT(*)>=@d)
      

  13.   

    --> --> (Andy)生成测试数据 2008-06-21 17:01:38  
    Set Nocount On
    declare @1 table([NAME] nvarchar(1),[DT] Datetime,[VAL] int)
    Insert @1
    select N'A','2008-06-17',N'10' union all
    select N'A','2008-06-16',N'09' union all
    select N'A','2008-06-15',N'08' union all
    select N'A','2008-06-14',N'06' union all
    select N'A','2008-06-13',N'-1' union all
    select N'A','2008-06-12',N'07' union all
    select N'A','2008-06-11',N'13' union all
    select N'B','2008-06-17',N'10' union all
    select N'B','2008-06-16',N'09' union all
    select N'B','2008-06-15',N'0' union all
    select N'B','2008-06-14',N'02' union all
    select N'B','2008-06-13',N'-1' union all
    select N'B','2008-06-12',N'07' union all
    select N'B','2008-06-11',N'10' union all
    select N'C','2008-06-17',N'0' union all
    select N'C','2008-06-16',N'09' union all
    select N'C','2008-06-15',N'0' union all
    select N'C','2008-06-14',N'06' union all
    select N'C','2008-06-13',N'225' union all
    select N'C','2008-06-12',N'150' union all
    select N'C','2008-06-11',N'100'
     ----1.查询在连续N天里val值大于M的员工及其相应的记录:
    Declare 
    @val int,
    @x int  Set @x=4 --天数
    Set @val=5
    ;With 
    t1 As
    (Select * From @1 a Where val>@val),
    t2 As
    (Select * From t1 a Where Exists(Select 1 From t1 Where name=a.name And dt>a.dt And dt<a.dt+@x Having Count(*)=@x-1))
    Select name,dt,val From t1 a
    Where Exists(Select 1 From t2 Where name=a.name And a.dt>=dt And a.dt<dt+@x )/*
    name dt                      val
    ---- ----------------------- -----------
    A    2008-06-17 00:00:00.000 10
    A    2008-06-16 00:00:00.000 9
    A    2008-06-15 00:00:00.000 8
    A    2008-06-14 00:00:00.000 6
    C    2008-06-14 00:00:00.000 6
    C    2008-06-13 00:00:00.000 225
    C    2008-06-12 00:00:00.000 150
    C    2008-06-11 00:00:00.000 100
    */--2各组答案中最接近今天的那条记录:
    ;With 
    t1 As
    (Select * From @1 a Where val>@val),
    t2 As
    (Select * From t1 a Where Exists(Select 1 From t1 Where name=a.name And dt>a.dt And dt<a.dt+@x Having Count(*)=@x-1)),
    t3 As
    (
    Select name,dt,val 
    From t1 a
    Where Exists(Select 1 From t2 Where name=a.name And a.dt>=dt And a.dt<dt+@x )
      
    )
    Select * From t3 a Where dt=(Select Max(dt) From t3 Where name=a.name)/*
    name dt                      val
    ---- ----------------------- -----------
    A    2008-06-17 00:00:00.000 10
    C    2008-06-14 00:00:00.000 6
    */--3.查询在连续N天里val值每天递增M%的员工及其相应的记录 Declare @y numeric(10,4) --百分比,这里使用小数表示
    Set @x=3
    Set @y=0.5
    ;With
    t1 As
    (Select id=Row_Number() Over(Partition By name Order By dt ),* From @1 a ),
    t2 As
    (Select a.*,y=Convert(numeric(10,4),case a.val When 0 Then Isnull(b.val,0) Else (Isnull(b.val*1.0,0)-a.val) /Abs(a.val) End) From t1 a Left Join t1 b On a.name=b.name And a.id+1=b.id),
    t3 As
    (Select * From t2 a Where y>=@y And Exists(Select 1 From t2 Where name=a.name And y>=@y And dt>a.dt And dt<a.dt+@x-1 Having Count(*)=@x-2 ))
    Select name,dt,val From t2 a
    Where Exists(Select 1 From t3 Where name=a.name And a.dt>=dt And a.dt<dt+@x )/*
    name dt                      val
    ---- ----------------------- -----------
    C    2008-06-11 00:00:00.000 100
    C    2008-06-12 00:00:00.000 150
    C    2008-06-13 00:00:00.000 225
    */
      

  14.   

    思路一样,套用了sql2005的cte语法
      

  15.   

    真是离开sql server太久了连什么是cte都不知道我的慢慢消化一下各位的高招这贴就先结了吧,等我完全搞清楚了再另外开帖送分给大家,到时如果还有什么问题,希望仍能得到各位的帮助。