Я думаю, это то, что вы хотите:
select distinct m.Name as MeterName,
min(dp.DateTime) over (partition by m.name) as FirstDateTime,
max(dp.DateTime) over (partition by m.name) as LastDateTime,
first_value(value) over (partition by m_name order by dp.datetime) as first_value,
first_value(value) over (partition by m_name order by dp.datetime desc) as last_value
from dbo.Meters m left join
dbo.DataPoints dp
on dp.MeterId = m.MeterId;
К сожалению, first_value()
(и last_value()
) не являются функциями агрегирования. Это один из редких случаев, когда использование select distinct
для агрегирования имеет смысл.
Для производительности вам нужны индексы на DataPonts(MeterId, datetime, value)
. Я бы также переписал условия как:
select distinct m.Name as MeterName,
min(dp.DateTime) over (partition by dp.MeterId) as FirstDateTime,
max(dp.DateTime) over (partition by dp.MeterId) as LastDateTime,
first_value(value) over (partition by dp.MeterId order by dp.datetime) as first_value,
first_value(value) over (partition by dp.MeterId order by dp.datetime desc) as last_value
from dbo.Meters m left join
dbo.DataPoints dp
on dp.MeterId = m.MeterId;
Я почти уверен, что MeterId
и MeterName
являются синонимами. Это позволит коду использовать индекс.
Другой метод, который может работать с тем же индексом:
select m.*, firstdp.*, lastdp.*
from dbo.Meters m outer apply
(select top (1) dp.datetime, dp.value
from dbo.DataPoints dp
where dp.MeterId = m.MeterId
order by datetime asc
) firstdp outer apply
(select top (1) dp.datetime, dp.value
from dbo.DataPoints dp
where dp.MeterId = m.MeterId
order by datetime desc
) lastdp;
С индексом я бы не удивился, если бы он был довольно быстрым.