有这样的三张表,记录表(id,compid 单位编号,happentime 发生时间,protypeid 问题类型),问题类型表(proid,……),单位表(compid单位编号,compname单位名称)。
要做一下三种统计:
一:统计某一时间段内某单位不同问题的汇总情况
选择好具体单位,起始时间、截止时间
生成一下这样的结果: 时间                问题1  问题2  问题3
2002(起始时间)   2     4      6
2003               6     8      1
2004(截止时间)   6     8      9
即统计一个单位在一个时间段内每年对应的问题类型的发生个数。二:统计某一时间段内各单位不同问题的汇总情况
选择好起始时间、截止时间生成这样的统计结果:单位    问题1  问题2  问题3
单位1    2      3      6    
单位2    4      5      7即统计不同单位在这段时间内对应的每种问题发生个数三:针对某个问题,统计某一时间段内各年度的汇总情况
选择开始时间、截止时间、问题分类生成以下这样结果:
单位   2002以前  2003 2004
单位1    12       4    23
单位2    29       3    12
即统计每个单位在这个时间段内每年某具体问题的发生情况
原来的做法是通过代码来设计好相应的datatable,然后在这个datatable里添加列,最后手动添加每条记录。这种方法比较死板,而且速度慢,因为每条记录的每个属性的值都是统计出来的。在oracle中有没有方式来实现这样的统计啊?
原先考虑过在oracle中生成临时表来做,原理和写代码设计datatable差不多。
如果在oracle中做,是不是要写些比较复杂的存储过程?

解决方案 »

  1.   

    是不是我没看懂,感觉只要用group by 就好了呀
      

  2.   

    1 select happentime,sum(decode(protypeid,'问题1',1)),sum(decode(protypeid,'问题2',1)),sum(decode(protypeid,'问题3',1)) from 表  where compid=*** group by happentime(如果时间包含年月日 ,则你按哪个分组就用SUBSTR去截断再GROUP)
    2, select B.compname,sum(decode(protypeid,'问题1',1)),sum(decode(protypeid,'问题2',1)),sum(decode(protypeid,'问题3',1)) from 记录表 A inner join 单位表 B
    on  A.compid=B. compid   group by B.compname
    3,  select B.compname,
    sum
    (case when 
    A.happentime <2002
    then 1
    else
    0 end ),sum
    (case when 
    A.happentime =2003
    then 1
    else
    0 end ),sum
    (case when 
    A.happentime =2004
    then 1
    else
    0 end ) from 记录表 A inner join 单位表 B
    on  A.compid=B. compid   group by B.compname好久没写SQL了``可能一俩个语法弄错一点 你自己调一下
      

  3.   

    1
    select to_char(a.happentime,'yyyy'),count(decode(a.protypeid,1,1))问题1,
      count(decode(a.protypeid,2,1))问题2,
      count(decode(a.protypeid,3,1))问题3
    from a
    where happentime between .. and ..
    group by to_char(a.happentime,'yyyy')
    2.
    select b.compname,count(decode(a.protypeid,1,1))问题1,
      count(decode(a.protypeid,2,1))问题2,
      count(decode(a.protypeid,3,1))问题3
    from a,b
    where a.id=b.compid
      and a.happentime between .. and ..
    group by b.compname
    3.
    select b.compname,count(case when a.happentime<date'2002-1-1' then 1 end)"2002以前",
      count(case when trunc(a.happentime,'yy')=date'2003-1-1' then 1 end)"2003",
      count(case when trunc(a.happentime,'yy')=date'2004-1-1' then 1 end)"2004"
    from a,b
    where a.id=b.compid
      and a.happentime between .. and ..
    group by b.compname
      

  4.   

    啊呀`郁闷  COUNT 写成SUM了呵呵`
      

  5.   

    不过请教狂浪 功能是否一样 SUM COUNT
      

  6.   


    问题类型的字段是不确定的!还有就是针对统计一,生成的表的记录按给定的时间段显示的,譬如是从2001年到2003年,则表记录如下:时间  问题1 ,问题2,……
    2001  3,    5,……
    2002  4,    8,……
    2003  2,    1,现在有个问题就是:怎么用select语句得到这样的一个查询结果,查询结果的字段是问题类型表的记录的一个属性值。
      

  7.   

    按给定的时间段? 
    那就BETWEEN 2001 AND 2003 GROUP BY YEAR就是了
    如果字段是不确定的就动态拼SQL啊 
     有几个字段 循环里添加上去
      

  8.   


    这个循环语句怎么写啊?以前遇到这种情况都是自己在程序中写代码生成datatable,太麻烦,速度还慢
      

  9.   

      --循环将项目ID传入语句
        FOR i in 1 .. type_field.COUNT LOOP
          v_sqlhead     := v_sqlhead ||
                           'to_char((select xmmc from t_xt_hmxmjbxxb where id=' ||
                           type_field(i) || '))';
          v_sqlbody     := v_sqlbody || 'to_char(SUM(decode(a.XMID,' ||
                           type_field(i) || ', a.JE,0)))';
          v_sqlbody     := v_sqlbody || ' je' || type_field(i);
          v_sqlbodyhead := v_sqlbodyhead || 'to_char(sum(t' || type_field(i) || '))';
          v_sqlname     := v_sqlname || 'nvl(je' || type_field(i) || ',0) t' ||
                           type_field(i);
          IF i < type_field.COUNT THEN
            v_sqlhead     := v_sqlhead || ',';
            v_sqlbody     := v_sqlbody || ',';
            v_sqlname     := v_sqlname || ',';
            v_sqlbodyhead := v_sqlbodyhead || ',';
          END IF;
          v_sqlhead     := v_sqlhead || CHR(13) || CHR(10);
          v_sqlbody     := v_sqlbody || CHR(13) || CHR(10);
          v_sqlname     := v_sqlname || CHR(13) || CHR(10);
          v_sqlbodyhead := v_sqlbodyhead || CHR(13) || CHR(10);
        END LOOP;
     这是一小段DEMO `不懂的再问我
      

  10.   


    你有qq或者msn么?刚接触动态sql,很菜
      

  11.   

     FOR i in 1 .. type_field.COUNT LOOP  
    这个是对type_field做循环 你不是查出所有的动态列了吗
    做循环 然后一个一个的加上去 拼SQL
      

  12.   

    本人也是菜鸟一个,接触oracle没几天
    研究了这么一个过程(只是针对问题一,二三应该类似),楼主看看有没有用create or replace
    PROCEDURE ABOUT_RECORD
      (    begindate IN char ,    enddate   IN char ,    compid_in    IN number ,  asql out VARCHAR2,  cur out sys_refcursor   )
    AS
      sql1 VARCHAR2(1000);
      sql2 varchar2(1000);
      cursor cur_t
      is
        select distinct protypeid from record where compid= compid_in order by protypeid;
    BEGIN
      FOR aRecord in cur_t
      LOOP
        sql1:= sql1 || ',sum(pt' || aRecord.protypeid || ') as 问题_' ||  aRecord.protypeid;
        sql2:= sql2 || ',case when protypeid=' || aRecord.protypeid || ' then 1 else 0 end as pt' || aRecord.protypeid;
      END LOOP;
      Asql:='select to_char(happentime,''yyyy'') as year' || sql1 ||
        ' from (select compid,happentime' || sql2 || 
        ' from record) a where compid=' || compid_in || 
        ' and happentime between to_date(''' || begindate || ''',''yyyymmdd'') and to_date(''' || 
        enddate || ''',''yyyymmdd'') group by to_char(happentime, ''yyyy'')';
      open cur for asql;
    END ABOUT_RECORD;在sqlplus中可以以下这样调用
    variable bd char(10);
    variable cur refcursor;
    variable ed     char(10);
    variable cid_in number;
    var asql varchar2(2000);
    begin
      :bd    :='20070101';
      :ed    :='20100101';
      :cid_in:=1;
    end ;
    /
    EXECUTE about_record(:bd,:ed,:cid_in,:asql,:cur);
    print :cur;
    print :asql;其中bd是起始日期,ed是终止日期,cin_in是单位id,asql就是动态拼成的sql语句
      

  13.   


    用了你的方法,但是cur如何关闭啊?
    打印了一次就不能再次打印了,还有,c#该怎么获取游标的值呢?并转成dataset啊?
      

  14.   

    还有,如果动态sql语句,过长,比4000还长咋办?