Sql 在oracle中统计表中的列数

Sql 在oracle中统计表中的列数,sql,oracle,Sql,Oracle,我有这种格式的表格。现在我需要计算第5个月和第6个月P的数量。我在第5个月需要所有的P,但在第6个月只需要P到第15天 我试过的代码是: create or replace PROCEDURE total_att IS cols varchar2(4000); col varchar2(4000); i number; where_str varchar2(4000); sqlstr varchar2(4000); BEGIN for

我有这种格式的表格。现在我需要计算第5个月和第6个月P的数量。我在第5个月需要所有的P,但在第6个月只需要P到第15天

我试过的代码是:

create or replace PROCEDURE total_att  IS
    cols varchar2(4000);
    col varchar2(4000);
    i number;
    where_str varchar2(4000);
    sqlstr varchar2(4000);
    BEGIN
    for i in 1..31 loop
    col:='day' || i;
    cols:=cols||col ||',';
    where_str:=where_str || col ||'=''P'' OR ';
    end loop;
    cols:=substr(cols,1,length(cols)-1);
    sqlstr:='SELECT MONTH,'||cols||' from hss_attendance where '|| where_str ;
    sqlstr:=substr(sqlstr,1,length(sqlstr)-3) ' ;
    dbms_output.put_line(sqlstr);
    END total_att;
我尝试的下一个代码是::

 create or replace PROCEDURE total_att_new  IS
    cols varchar2(4000);
    col varchar2(4000);
    i number;
    where_str varchar2(4000);
    sqlstr varchar2(4000);
    sqlstrs clob;
    BEGIN
    for i in 1..32 loop
    col:='day' || i;
    sqlstr:='select month,
    case '||col||' when ''P''
    then 1 else 0 end as att
    from hss_attendance
    where student_id = ''4003''
    and month=''4''
    union ';
    sqlstrs:=sqlstrs || sqlstr;
    end loop;
    dbms_output.put_line(sqlstrs);
    END total_att_new;

这可能是一种不需要动态SQL的方法:

SELECT count(case when value = 'P' then 1 end)
FROM   horribleTable
UNPIVOT (value FOR dy IN (
                            DAY1  as '1',
                            DAY2  as '2',
                            DAY3  as '3',
                            DAY4  as '4',  
                            DAY5  as '5',
                            DAY6  as '6',
                            DAY7  as '7',
                            DAY8  as '8',
                            DAY9  as '9',
                            DAY10 as '10',
                            DAY11 as '11',
                            DAY12 as '12',
                            DAY13 as '13',
                            DAY14 as '14',
                            DAY15 as '15',
                            DAY16 as '16',
                            DAY17 as '17',
                            DAY18 as '18',
                            DAY19 as '19',
                            DAY20 as '20',
                            DAY21 as '21',
                            DAY22 as '22',
                            DAY23 as '23',
                            DAY24 as '24',
                            DAY25 as '25',
                            DAY26 as '26',
                            DAY27 as '27',
                            DAY28 as '28',
                            DAY29 as '29',
                            DAY30 as '30',
                            DAY31 as '31')
)
where (mth = 5 or (mth = 6 and dy <= 15))
  and yr = 2016    --  optional
;
选择计数(值为'P'然后为1结束时的情况)
从可怕的桌子
UNPIVOT(单位为dy的值)(
第1天为“1”,
第2天为“2”,
第3天为“3”,
第4天为“4”,
第5天为“5”,
第6天为“6”,
第7天为“7”,
第8天为“8”,
第9天为“9”,
第10天为“10”,
第11天为“11”,
第12天为“12”,
第13天为“13”,
第14天为“14”,
第15天为“15”,
第16天为“16”,
第17天为“17”,
第18天为“18”,
第19天为“19”,
第20天为“20”,
第21天为“21”,
第22天为“22”,
第23天为“23”,
第24天为“24”,
第25天为“25”,
第26天为“26”,
第27天为“27”,
第28天为“28”,
第29天为“29”,
第30天为“30”,
第31天为“31”)
)

其中(mth=5或(mth=6和dy表的设计很糟糕,但相应地查询很长,但仍然很容易:

select month,
  case when day1 = 'P' then 1 else 0 end +
  case when day2 = 'P' then 1 else 0 end +
  case when day3 = 'P' then 1 else 0 end +
  case when day4 = 'P' then 1 else 0 end +
  ...
  case when day31 = 'P' then 1 else 0 end as days
from mytable
where month = 5
union all
select month,
  case when day1 = 'P' then 1 else 0 end +
  case when day2 = 'P' then 1 else 0 end +
  case when day3 = 'P' then 1 else 0 end +
  case when day4 = 'P' then 1 else 0 end +
  ...
  case when day15 = 'P' then 1 else 0 end as days
from mytable
where month = 6
这将为您提供每月的金额。如果您希望两个月都有一笔金额,请执行以下操作:

select month,
  case when day1 = 'P' then 1 else 0 end +
  case when day2 = 'P' then 1 else 0 end +
  case when day3 = 'P' then 1 else 0 end +
  case when day4 = 'P' then 1 else 0 end +
  ...
  case when day15 = 'P' then 1 else 0 end +
  case when month = 5 and day16 = 'P' then 1 else 0 end +
  case when month = 5 and day17 = 'P' then 1 else 0 end +
  ...
  case when month = 5 and day31 = 'P' then 1 else 0 end as days
from mytable
where month in (5, 6);
下面是给定的第二个查询:from_month、:from_day、:till_month、:till_day:

select month,
  case when day1 = 'P' 
       and not (month = :from_month and 1 < :from_day)
       and not (month = :till_month and 1 > :till_day)
  then 1 else 0 end +
  case when day2 = 'P'
       and not (month = :from_month and 2 < :from_day)
       and not (month = :till_month and 2 > :till_day)
  then 1 else 0 end +
  ...
  case when day31 = 'P'
       and not (month = :from_month and 31 < :from_day)
       and not (month = :till_month and 31 > :till_day)
  then 1 else 0 end as days
from mytable
where month between :from_month and :till_month;
选择月份,
第1天为'P'时的情况
与否(月=:从月开始,1<:从日开始)
而不是(月=:至月和1>:至日)
然后1或0结束+
第2天为'P'时的情况
与否(月=:自月和2<:自日)
而不是(月=:至月和2>:至日)
然后1或0结束+
...
第31天为'P'时的情况
而不是(月=:从月开始,31<:从日开始)
而不是(月=:至月和31>:至日)
然后1或0以天结束
从mytable
其中月份介于:从月到月之间;

但最好改变表的设计,这样查询会简单得多,键入的内容也会少很多:-)

这看起来像是非常糟糕的表设计。这将如何扩展多年?关于你的问题,你可能需要一些动态SQL在这里通过
DAY
加上一些数字构建名称来过滤你想要的列。在这个表中,我还有一些列,包括year。在这张图中,我只放了month和DAY列。当然,我期待动态查询。请将数据作为格式化测试发布。另外,到目前为止您尝试了什么?请发布您的代码并解释您遇到的问题。在这个请求中,您询问如何计算5月1日至6月15日的Ps之和。现在,它显示了您真正想问的是如何计算日期范围内的Ps之和在运行查询时指定了。这是完全不同的,因此下次发出请求时请多加注意。您不需要“动态SQL”或“过程”对于这一点,列是固定的。正确的解决方案是规范化表设计,但通过您现在所拥有的,Aleksej已经向您展示了如何在纯SQL中实现这一点。任何其他解决方案都比简单地先取消激活(使数据正常以便进一步处理)更难维护,效率也更低。这是一种静态查询。日和月将作为输入参数,因此它可以是1到31之间的任何一天,也可以是1到12之间的任何一个月,因此如果您能帮助我,我需要动态查询您需要这两个查询中的哪一个;每月一个总数还是一个总和?我需要P的总数。如果输入参数是第6个月和第15天,那么我需要总数从第一个月到第六个月的第15个月,我在我的答案中添加了这样一个查询。你会注意到,只有变量是一样的。什么是“仍然不起作用”意思?一个错误?一个不正确的总数?还有什么?你甚至检查过这个查询以找出它的错误吗?我编辑了两件事的代码:第一,OP想要第5个月的所有天和第6个月的前15天(因此
month=5和day<15
都是不正确的).和,
day
month
year
都是Oracle中的保留字,不应用于列名。我将列名更改为
dy,mth,yr
。在这种情况下,您也可以简单地
计数(值)
(假设其他“值”为空).UNPIVOT不会为空值创建行-即使创建了,
count(列名)
在计数中不包括空值。@mathguy-完全正确,谢谢。对于值,OP似乎可以有类似“A”的值,所以我更喜欢保留一些他可以轻松适应的值。我使用toad For oracle。当我使用上述查询时,它并没有将UNPIVOT作为关键字,因此它说:ORA-00933:SQL命令未正确结束ed@AnilBirSinghTuladhar当前位置我相信这不是蟾蜍的问题。哪个Oracle版本?