2017-01-26 3 views
0

Я использую этот запрос, чтобы получить среднечасовое значение и, похоже, работает нормально.Получите минутное среднее значение

select Time_Stamp_Hour = dateadd(hh,datepart(hh,Time_Stamp), cast(CAST(Time_Stamp as date) as datetime)) 
     ,AvgValue = AVG(Value) 
from ValueLog 
group by dateadd(hh,datepart(hh,Time_Stamp) 
     ,cast(CAST(Time_Stamp as date) as datetime)) 

Мне нужно получить средние значения за минуточку за весь день, поэтому полученные результаты за один день должны иметь 1440 записей.

Я попытался переключить hh на mi, но он просто дает мне в среднем 60 индивидуальных минут на весь день без ежедневного пробоя. Как бы преобразовать это утверждение в минутные средние за каждый час дня. Я использую SQL Server 2012.

sample result when using mi instead of hh

час колонки не возвращает правильный час (только показывает 00) при использовании миль вместо чч и выше заявление, и я только получить 60 результатов в день.

Вот пример того, когда я запускаю вышеуказанный оператор с hh как мое условие, которое результаты показывают правильно.

hh

+0

Что вы подразумеваете под «минутами»? – iamdave

+0

Можете ли вы добавить добавить [MCVE] (http://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve-for-what-seems-to-me-to-be- a-very-simple-sql-query) к этому вопросу? –

+0

У меня есть таблица с двумя столбцами, меткой времени и значением образца, которая записывается каждые несколько секунд. Я могу использовать вышеприведенный оператор select, чтобы получить почасовое среднее значение этих выборок. Мне нужно сделать этот шаг дальше и получить поминутные средние значения. –

ответ

1

усечение секунд от метки времени, используйте: dateadd(minute, datediff(minute, 0, Time_Stamp), 0)

select Time_Stamp_Hour_Minute = dateadd(minute, datediff(minute, 0, Time_Stamp), 0) 
    , AvgValue = avg(Value) 
from ValueLog 
group by dateadd(minute, datediff(minute, 0, Time_Stamp), 0) 

Вы также мог бы заменить выражение в вашем вопросе укоротить на час dateadd(hour, datediff(hour, 0, Time_Stamp), 0).


Использование convert(varchar(5),time_stamp,8) возвращает время, как hh:mi, что это то, что это звучит, как вы пытаетесь сделать. Стиль 8 возвращает формат hh:mi:ss, и преобразование его в varchar (5) ограничивает его до первых 5 символов (hh:mi).

select Time_Stamp_Hour_Minute = convert(varchar(5),Time_Stamp,8) 
     , AvgValue = avg(Value) 
from ValueLog 
group by convert(varchar(5),Time_Stamp,8) 

ссылка: cast() and convert() styles

+0

Я думаю, что вы дали мне ответ, который я искал, урезая секунды и миллисекунды от моих временных меток. Это должно позволить мне запускать if statement в отношении других условий, которые есть в базе данных.Это другой способ атаковать проблему, но я думаю, что это сработает. –

+0

@PatPav Рад помочь! – SqlZim

0

Если вы ищете "TWA" время средневзвешенное, Проверьте монстра. Я построил это для интерфейса для своего пакета SCADA. С помощью этого запроса вы не ограничены стандартными интервалами 1 мин, 1 день, 1 час. Вы можете изменить @i, чтобы получить желаемый интервал. Основная задача запроса - обрабатывать отсутствующие интервалы, если они существуют в вашей таблице. I.E, если у вас было значение в 1 утра, но не было другого значения до 8AM ... ect ...

ПРИМЕЧАНИЕ. Удалите окончательный оператор выбора и сделайте COMBINE вашим окончательным оператором выбора, чтобы посмотреть, что происходит. Вы можете скопировать и вставить ниже непосредственно в SQL Server и без изменений. В вашем случае измените @i равным 1, удачи.

--Create the test table! Add any values you want! 
DECLARE @TEST001 TABLE (Time_Stamp datetime, TagA INT, TagB INT, TagC INT, TagD INT, TagE INT, TagF INT) 
-- Insert test Values so we can test what is going on with the monster query below.  
INSERT INTO @TEST001 
VALUES 
    ('2017-01-21 00:01:09.042', NULL, NULL, NULL, 7000, NULL, NULL), 
    ('2017-01-21 00:02:03.042', NULL, NULL, 87, NULL, NULL, NULL), 
    ('2017-01-21 00:04:10.155', NULL, 1239, NULL, NULL, NULL, NULL), 
    ('2017-01-21 00:04:10.959', NULL, NULL, 86, NULL, NULL, NULL), 
    ('2017-01-21 00:06:49.401', NULL, 1240, NULL, NULL, NULL, NULL), 
    ('2017-01-21 00:06:59.301', 100, 1239, NULL, NULL, NULL, NULL), 
    ('2017-01-21 00:07:00.000', 109, NULL, NULL, NULL, NULL, NULL), 
    ('2017-01-21 00:07:10.124', 108, NULL, NULL, NULL, NULL, NULL), 
    ('2017-01-21 00:12:11.789', 109, NULL, NULL, NULL, NULL, NULL), 
    ('2017-01-21 00:16:12.190', 108, NULL, NULL, NULL, NULL, NULL), 
    ('2017-01-21 00:16:13.987', 107, NULL, NULL, NULL, NULL, NULL), 
    ('2017-01-21 00:17:31.410', NULL, 1260, NULL, NULL, NULL, NULL), 
    ('2017-01-21 00:17:32.511', NULL, 1261, 87, NULL, NULL, NULL), 
    ('2017-01-21 00:17:32.966', NULL, 1262, NULL, NULL, NULL, NULL), 
    ('2017-01-21 00:18:53.140', NULL, 1262, NULL, NULL, 6000, NULL) 

-- Begin of our query. NOTE to Tech's, The above is not needed WHEN using real table data. 
-- To query real data change #TEST001 to your real table data. and TagA to your desired column. 
declare @s DATETIME2 --Start date and time 
declare @e DATETIME2 --End date and time 
declare @i INT -- Holds our desired interval. if you set to 60 you will get hour intervals, set to 1440 to get daily intervals. 
       -- set to 120 for every two hours 
       -- set to 2880 for every 2 days... 
set @s = '2017-01-21 00:00:00.000' 
set @e = '2017-01-21 23:59:59.000' 
set @i = 60 

--TIME GENERATOR, Generates all times between our start and end date. 
;WITH ALL_INTERVALS 
AS (
    SELECT TOP (DATEDIFF(MINUTE,@s,@e)) 
    TIMES = DATEADD(MINUTE,CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id])-1),@s), 
    NULL AS VALUE 
     FROM sys.all_objects AS s1 
     CROSS JOIN 
     sys.all_objects AS s2 
), 
--Union All possable times from our generator with all real data from our table. 
ALL_TIMES 
AS (
SELECT 
     H.Time_Stamp as TIMES, 
     H.TagA AS VALUE 
    FROM @TEST001 H 
    WHERE Time_Stamp BETWEEN @s and @e 
    UNION ALL 
    SELECT 
     AI.TIMES AS TIMES, 
     AI.VALUE AS VALUE 
     FROM ALL_INTERVALS AI   
), 
-- We need to fill across, up and down. 
-- TIMES=AT.TIMES, just inCASE our generated time is equal to our real data time. 
-- TIMES>AT.TIMES Fill nulls in the upward dirrection. 
-- TIMES>AT.TIMES Fill nulls in the downward dirrection. 
FILL_UP_DOWN_ACCROSS 
AS ( 
    SELECT 
    TIMES AS TIMES, 
    VALUE AS VALUE1, 
    ISNULL(AT.VALUE, (SELECT TOP 1 VALUE FROM ALL_TIMES WHERE TIMES = AT.TIMES AND VALUE IS NOT NULL ORDER BY TIMES ASC)) AS VALUE2, 
    ISNULL(AT.VALUE, (SELECT TOP 1 VALUE FROM ALL_TIMES WHERE TIMES > AT.TIMES AND VALUE IS NOT NULL ORDER BY TIMES ASC)) AS VALUE3, 
    ISNULL(AT.VALUE, (SELECT TOP 1 VALUE FROM ALL_TIMES WHERE TIMES < AT.TIMES AND VALUE IS NOT NULL ORDER BY TIMES DESC)) AS VALUE4 
    FROM ALL_TIMES AT 
), 
-- COMBINE, Select all non null values. The value1,2,3 can be removed! As they are not needed in the final select statement. 
-- I just have them here for quickly viewing what is going on if i make this COMBINE statement as my final select statement. 
COMBINE 
AS (
SELECT TIMES, 
     VALUE1, 
     VALUE2, 
     VALUE3, 
     VALUE4, 
     COALESCE(CASE WHEN FUDA.VALUE2 IS NULL AND FUDA.VALUE4 IS NULL THEN (FUDA.VALUE3) ELSE FUDA.VALUE2 END, 
        CASE WHEN FUDA.VALUE2 IS NULL AND FUDA.VALUE3 IS NULL THEN (FUDA.VALUE4) ELSE FUDA.VALUE2 END, 
        CASE WHEN FUDA.VALUE2 IS NULL AND FUDA.VALUE4 IS NOT NULL THEN (FUDA.VALUE4) ELSE FUDA.VALUE2 END 
       ) AS VALUE5 
     FROM FILL_UP_DOWN_ACCROSS FUDA 
) 
--Final Select Statement, do the TWA! 
--DO TIME WEIGHED AVERAGE. 
SELECT DATEADD(MINUTE,((DATEDIFF(MINUTE,@s,TIMES)/@i)*@i),@s) AS TIMES, 
SUM(CONVERT(FLOAT,CAST(TIMES AS DATETIME)) * VALUE5)/SUM(CONVERT(FLOAT,CAST(TIMES AS DATETIME))) AS TagAvg 
FROM COMBINE 
GROUP BY DATEADD(MINUTE,((DATEDIFF(MINUTE,@s,TIMES)/@i)*@i),@s) 
ORDER BY DATEADD(MINUTE,((DATEDIFF(MINUTE,@s,TIMES)/@i)*@i),@s)