Я прошу прощения, если мой вопрос может быть дан ответ в другом месте, я просто не уверен, что искать, чтобы узнать, если он был дан ответ в другом месте. Я новичок в SQL, и я пытался сделать запрос к БД, которая показывает время безотказной работы системы клиента в процентах, которое существует в таблице БД, и сообщить об этом как среднее значение за этот месяц, а также о прошлой производительности за предыдущий месяцы.

Например, я беру среднее значение за месяц и отображаю его для каждого месяца, но затем делаю для прошедшего года, основываясь на текущем месяце (то есть, март, февраль, январь и т. Д.), Всегда ровно год прошлой работы.

Вот мой текущий сценарий, который я получил для среднемесячного расчета на основе идентификатора клиента .... Теперь я хотел бы показать показатели прошлых лет, подобные этим, для каждого месяца:

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
0
Fadiddy 21 Мар 2017 в 21:44

2 ответа

Лучший ответ

У вас есть вызов агрегатной функции avg(), и вы уже группируете по неагрегированному столбцу в списке выбора. Чтобы получить данные за каждый месяц за последний год (кажется, до конца предыдущего месяца), вам просто нужно включить месяц в список выбора и предложения group-by:

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') дает вам полночь первого дня месяца для значения этого столбца. Это можно использовать для группировки, поэтому все даты в месяце считаются первыми в один и тот же день. В списке выбора это же выражение затем может быть преобразовано в строку, содержащую только название месяца. (Я предполагал, что ваша сессия на английском языке, но есть третий аргумент для to_char() чтобы справиться с этим, если нет).

Линия

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-claus верно, вы можете сделать:

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().

0
Alex Poole 21 Мар 2017 в 19:23

Вам просто нужно добавить месяц, чтобы выбрать и сгруппировать по:

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"; 
0
Anand 21 Мар 2017 в 19:09