热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

超有难度的sql,200分奉上!

数据很简单:maxvalue80901017115120max值自8开始,逐行递增1每行的value不允许超过max值,超过部
数据很简单:
max  value
8    0
9    0
10   17
11   5
12   0

max值自8开始,逐行递增1
每行的value不允许超过max值,超过部分计入下行,以此类推
要求结果为
8    0
9    0
10   10
11   11
12   1


说明,不一定仅此五行,后面的可以按max规律再加

15 个解决方案

#1


-- 用SQL很难,游标处理是最好的啦!

#2


坐等达人…

#3



/*
抛砖引玉吧
缺陷m列(即你的max列只能是从8开始按1递增

楼主执行这个过程前做好备份
*/
create or replace procedure scott.update_pro
as
n_flag number;
n_cnt number;
n_m test.m%type;
n_v test.v%type;
begin
n_flag:=0;
select count(*) into n_cnt from test;
for i in 8..7+n_cnt loop
select m,v into n_m,n_v from test where m=i;
if n_v+n_flag<=n_m then
update test set v=n_v+n_flag
where m=i;
else
update test set v=m
where m=i;
n_flag:=n_v+n_flag-n_m;
end if;
end loop;
commit;
exception
   when others then
   dbms_output.put_line(sqlerrm);
end;

--执行过程前
select * from test;
     M          V
------ ----------
     8          0
     9          0
    10         17
    11          5
    12          0

--执行过程后
 select * from test;

         M          V
---------- ----------
         8          0
         9          0
        10         10
        11         11
        12          1

#4



--初始数据:
select * from tmp;

MAX      Value
------------------
8         0
9         0
10        17
11        5
12        0
13        26
14        13
15        12
16        3


--执行如下匿名PLSQL块:

declare
   cnt number;
   val number;
begin
   select count(*) into cnt from tmp where value>max;
   while cnt>0 loop
         for rs in (select * from tmp where value>max ) loop
             val := rs.value-rs.max;
             update tmp set value=max where max=rs.max;
             update tmp set value=value+val where max=rs.max+1;
             commit;
         end loop;
         select count(*) into cnt from tmp where value>max;
   end loop;
end;

--结果:
select * from tmp;

MAX      Value
-----------------
8         0
9         0
10        10
11        11
12        1
13        13
14        14
15        15
16        12

#5



--再修改下,假设你value值很大,导致你max没有那么多需要分摊,自动新增:

--原数据:
--注意没有max=16的
select * from tmp;
MAX   Value
-------------
8   0
9   0
10      17
11   5
12   0
13   26
14   13
15   12


--执行如下匿名块:
declare
   cnt number;
   val number;
begin
  select count(*) into cnt from tmp where value>max;
  while cnt>0 loop
      for rs in (select * from tmp where value>max ) loop
          val := rs.value-rs.max;
          update tmp set value=max where max=rs.max;
          update tmp set value=value+val where max=rs.max+1;
          if sql%rowcount!=1 then
             insert into tmp(max,value) values(rs.max+1,val);  --新增
          end if;
          commit;
      end loop;
      select count(*) into cnt from tmp where value>max;
  end loop;
end;

--结果:
select * from tmp;
MAX   Value
-----------------
8   0
9   0
10   10
11   11
12   1
13   13
14   14
15   15
16   9    --新增的分摊数据

#6


感谢zhuomingwang、gelyon大大的回复,用存储过程、匿名块等方式的确可以解决我们这个问题!
但是有一个问题,我的数据源不是直接从表里的读取出来的,数据源本身就是统计出来的,用sql的方式能否实现。如果实在实现不了,我该如何解决?

#7


--试一下SQL解决,表名为t
select max,decode(tmp1,-1,tmp,max) val from (
  select max,v,tmp,tmp1 from 
    (select max,val val from t order by max)
  model
  dimension by (max)
  measures (val v,max m,0 as tmp,0 as tmp1)
    rules(
      tmp[any]= case when v[cv()-1] is null then
        case when v[cv()]>m[cv()] then
          v[cv()]-m[cv()]
        else
          v[cv()]
        end
      else
        case when tmp[cv()-1]+v[cv()]>m[cv()] then
          tmp[cv()-1]+v[cv()]-m[cv()]
        else
          tmp[cv()-1]+v[cv()]
        end
      end,
      tmp1[any]= case when v[cv()-1] is null then
        case when v[cv()]>m[cv()] then 1 else -1 end
      else
        case when tmp[cv()-1]+v[cv()]>m[cv()] then 1 else -1 end
      end
    )

#8


引用 7 楼 tangren 的回复:
SQL code
--试一下SQL解决,表名为t
select max,decode(tmp1,-1,tmp,max) val from (
  select max,v,tmp,tmp1 from 
    (select max,val val from t order by max)
  model
  dimension by (max)
  measures (val v,……

tangren大大厉害,基本上效果达到了,我刚刚测试了,基本上OK,有一组数据有点问题,tangren大大是不是有个别情况没有考虑到呢^_^
我先来消化消化

with t as (
select 8 max,0 val from dual
union all
select 9,0 from dual
union all
select 10,17 from dual
union all
select 11,12 from dual
union all
select 12,0 from dual
union all
select 13,18 from dual
union all
select 14,0 from dual
)

#9


修改了一下^_^
select max,case when tmp>max then max else tmp end val from (
  select max,v,tmp from 
    (select max,val val from t order by max)
  model
  dimension by (max)
  measures (val v,max m,0 as tmp)
    rules(
      tmp[any]= case when v[cv()-1] is null then
          v[cv()]
      else
        case when tmp[cv()-1]>m[cv()-1] then
          tmp[cv()-1]-m[cv()-1]+v[cv()]
        else
          v[cv()]
        end
      end
    )
)

还有没有其他sql方法呢

#10


你之前的统计不能变通下来实现需求么?

#11


该回复于2011-03-10 13:04:39被版主删除

#12


引用 9 楼 lihui_shine 的回复:
修改了一下^_^
SQL code
select max,case when tmp>max then max else tmp end val from (
  select max,v,tmp from 
    (select max,val val from t order by max)
  model
  dimension by (max)
  measures (val v,……

优化得不错,我写复杂了哈~~~

#13


该回复于2011-03-10 14:14:47被版主删除

#14


引用 10 楼 minitoy 的回复:
你之前的统计不能变通下来实现需求么?

我是做的年假统计,给我的数据,只有入职日期、休假的明细表。
年假嘛,大家都懂的,有时间限制的,过时不休视为自动放弃,我需要统计的是每个年周期已休记录数、可休天数。兄台有什么好的办法?

比如我是2008-12-01入职的,到2009-12-01开始我可以休8天,截止日期到2010-11-30日,
2009-12-01至2010-11-30,我有9天的年假,截止日期到2011-11-30日,
以此类推
除了第一年要满一年外外,以后每年的年假可休时间都是按照已过月份/12*年周期年假天数

#15


今天晚上结贴,如果大家想挑战下,有新的方法的话,我可以另外开贴给分

推荐阅读
  • 本文介绍了Oracle存储过程的基本语法和写法示例,同时还介绍了已命名的系统异常的产生原因。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • 本文介绍了如何在MySQL中将零值替换为先前的非零值的方法,包括使用内联查询和更新查询。同时还提供了选择正确值的方法。 ... [详细]
  • Oracle分析函数first_value()和last_value()的用法及原理
    本文介绍了Oracle分析函数first_value()和last_value()的用法和原理,以及在查询销售记录日期和部门中的应用。通过示例和解释,详细说明了first_value()和last_value()的功能和不同之处。同时,对于last_value()的结果出现不一样的情况进行了解释,并提供了理解last_value()默认统计范围的方法。该文对于使用Oracle分析函数的开发人员和数据库管理员具有参考价值。 ... [详细]
  • 本文详细介绍了在ASP.NET中获取插入记录的ID的几种方法,包括使用SCOPE_IDENTITY()和IDENT_CURRENT()函数,以及通过ExecuteReader方法执行SQL语句获取ID的步骤。同时,还提供了使用这些方法的示例代码和注意事项。对于需要获取表中最后一个插入操作所产生的ID或马上使用刚插入的新记录ID的开发者来说,本文提供了一些有用的技巧和建议。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文讨论了在数据库打开和关闭状态下,重新命名或移动数据文件和日志文件的情况。针对性能和维护原因,需要将数据库文件移动到不同的磁盘上或重新分配到新的磁盘上的情况,以及在操作系统级别移动或重命名数据文件但未在数据库层进行重命名导致报错的情况。通过三个方面进行讨论。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • 本文讨论了如何使用IF函数从基于有限输入列表的有限输出列表中获取输出,并提出了是否有更快/更有效的执行代码的方法。作者希望了解是否有办法缩短代码,并从自我开发的角度来看是否有更好的方法。提供的代码可以按原样工作,但作者想知道是否有更好的方法来执行这样的任务。 ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • Java学习笔记之使用反射+泛型构建通用DAO
    本文介绍了使用反射和泛型构建通用DAO的方法,通过减少代码冗余度来提高开发效率。通过示例说明了如何使用反射和泛型来实现对不同表的相同操作,从而避免重复编写相似的代码。该方法可以在Java学习中起到较大的帮助作用。 ... [详细]
author-avatar
yanna00799
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有