Если вы ищете "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)
Что вы подразумеваете под «минутами»? – iamdave
Можете ли вы добавить добавить [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) к этому вопросу? –
У меня есть таблица с двумя столбцами, меткой времени и значением образца, которая записывается каждые несколько секунд. Я могу использовать вышеприведенный оператор select, чтобы получить почасовое среднее значение этих выборок. Мне нужно сделать этот шаг дальше и получить поминутные средние значения. –