SQL脚本按月显示过去的数据

时间:2017-03-21 18:44:56

标签: sql oracle oracle11g

如果我的问题可以在其他地方得到解答,我道歉,我只是不确定要搜索什么,以了解它是否已在其他地方得到解答。我是SQL新手,并且一直在尝试查询数据库,该数据库显示基于DB表中存在的百分比的客户系统正常运行时间,并将其报告为该月的平均值,以及之前的过去性能个月。

例如,我需要一个月的平均值并且每个月显示一次,但是根据当前月份(即3月,2月,1月等等)过去一年的情况呢...总是过去表现的一年

这是我目前的脚本,我根据客户ID开始工作一个月的平均值....我现在想要显示过去几年每个月的表现:

SQL查询:

select   cast (avg("DATA_POINT_DATA"."VALUE") as int) as "UP_VALUE",
"DATA_POINT_DATA"."UPLOAD_DATA_ID" as "CUSTOMER_ID"
 from   "DB_TABLE"."DATA_POINT_DATA" "DATA_POINT_DATA",
    "DB_TABLE"."CALC_DATA" "CALC_DATA" 
 where   "DATA_POINT_DATA"."CALC_DATA_ID"="DATA_POINT_DATA"."ID"
  and    "CALC_DATA"."NAME" ='CustomerUp' 
   and   "DATA_POINT_DATA"."UPLOAD_DATA_ID" in ('123abc')
   and  "UPLOAD_TIME" between ('01-FEB-17') and ('28-FEB-17') 
   group by "DATA_POINT_DATA"."UPLOAD_DATA_ID";

查询输出:

UP_VALUE    CUSTOMER_ID
-------- --------------
     100         123abc

预期产出:

MONTH    UP_VALUE    CUSTOMER_ID
----- ----------- --------------
FEB           100         123abc
JAN           100         123abc
DEC           100         123abc
NOV            90         123abc
OCT           100         123abc
SEP           100         123abc
AUG           100         123abc
JUL            89         123abc
JUN           100         123abc
MAY            75         123abc
APR           100         123abc
MAR           100         123abc
FEB            90         123abc

2 个答案:

答案 0 :(得分:0)

您只需添加月份来选择和分组:

SELECT datepart(upload_time, DP_MONTH) as upload_month, Cast (Avg("data_point_data"."value") AS INT) AS "UP_VALUE", 
       "data_point_data"."upload_data_id" AS "CUSTOMER_ID" 
FROM   "DB_TABLE"."data_point_data" "DATA_POINT_DATA", 
       "DB_TABLE"."calc_data" "CALC_DATA" 
WHERE  "data_point_data"."calc_data_id" = "data_point_data"."id" 
       AND "calc_data"."name" = 'CustomerUp' 
       AND "data_point_data"."upload_data_id" IN ( '123abc' ) 
       AND "upload_time" BETWEEN ( '01-FEB-17' ) AND ( '28-FEB-17' ) 
GROUP  BY datepart(upload_time, DP_MONTH), "data_point_data"."upload_data_id"; 

答案 1 :(得分:0)

您有一个聚合avg()函数调用,并且您已经按选择列表中的非聚合列进行分组。要获取去年每个月的数据(直到上个月结束,它出现),您只需要在选择列表和分组条款中包含月份:

select to_char(trunc("UPLOAD_TIME", 'MM'), 'MON') as "MONTH",
  cast (avg("DATA_POINT_DATA"."VALUE") as int) as "UP_VALUE",
  "DATA_POINT_DATA"."UPLOAD_DATA_ID" as "CUSTOMER_ID"
from "DB_TABLE"."DATA_POINT_DATA" "DATA_POINT_DATA",
  "DB_TABLE"."CALC_DATA" "CALC_DATA" 
where "DATA_POINT_DATA"."CALC_DATA_ID"="DATA_POINT_DATA"."ID"
and "CALC_DATA"."NAME" ='CustomerUp' 
and "DATA_POINT_DATA"."UPLOAD_DATA_ID" in ('123abc')
and "UPLOAD_TIME" between ('01-MAR-16') and ('28-FEB-17') 
group by trunc("UPLOAD_TIME", 'MM'), "DATA_POINT_DATA"."UPLOAD_DATA_ID";

表达式trunc("UPLOAD_TIME", 'MM')为您提供该列值的当月第一天午夜。这可以用于分组,因此一个月中的所有日期都被视为在同一天,即第一天。在选择列表中,可以将同一表达式转换为仅显示月份名称的字符串。 (我假设您的会话是英语,但如果没有,则会a third argument to to_char() to handle that。)

该行

where "DATA_POINT_DATA"."CALC_DATA_ID"="DATA_POINT_DATA"."ID"

看起来很奇怪,而且目前你似乎没有任何真正的连接条件;我怀疑应该是:

where "DATA_POINT_DATA"."CALC_DATA_ID"="CALC_DATA"."ID"

但也许不是。

执行以下操作时,您依赖于会话NLS设置:

and  "UPLOAD_TIME" between ('01-FEB-17') and ('28-FEB-17') 

您应该使用明确的to_date()调用和格式掩码,并且最好不要假设会话语言是英语(这会影响月份名称处理),但至少应该这样做:

and  "UPLOAD_TIME" between to_date('01-FEB-17', 'DD-MON-RR')
  and to_date('28-FEB-17', 'DD-MON-RR') 

...但即使在这里,也可以使用4位数的年份,如果您的任何列值在午夜之后有时间,那么您将丢失2017-02-28 00:00:01之类的数据

您也不需要在此处使用所有对象名称的双引号;没有它们,对象名称的情况并不重要,这可能会使它更容易阅读。您还应该使用ANSI连接语法;假设上面的where-clause观察是正确的,你可以这样做:

select to_char(trunc(upload_time, 'MM'), 'MON') as month,
  cast (avg(data_point_data.value) as int) as up_value,
  data_point_data.upload_data_id as customer_id
from db_table.data_point_data
join db_table.calc_data
on data_point_data.calc_data_id=calc_data.id
where calc_data.name ='CustomerUp' 
and data_point_data.upload_data_id = '123abc'
and upload_time >= add_months(trunc(sysdate, 'MM'), -12)
and upload_time < trunc(sysdate, 'MM')
group by trunc(upload_time, 'MM'), data_point_data.upload_data_id
order by trunc(upload_time, 'MM') desc;

对于我根据当前日期的日期范围,并使用>=<代替between,以避免非午夜时间出现问题。您可以使用以下命令查看这些表达式评估的值:

select to_char(add_months(trunc(sysdate, 'MM'), -12), 'YYYY-MM-DD HH24:MI:SS') as from_time,
  to_char(trunc(sysdate, 'MM'), 'YYYY-MM-DD HH24:MI:SS') as to_time
from dual;

FROM_TIME           TO_TIME            
------------------- -------------------
2016-03-01 00:00:00 2017-03-01 00:00:00

最后,cast(... as int)有点不寻常;根据您希望如何处理小数部分,您还可以查看trunc()ceil()floor()