Reputation: 79
I have a Parameters Log
table like this:
Log ID | Temperature | Humidity | country | Date |
---|---|---|---|---|
1 | 40 | 10 | USA | 2021-09-04 10:00:51.737 |
2 | 20 | 20 | USA | 2021-09-04 11:09:51.737 |
3 | 30 | 30 | USA | 2021-09-04 12:09:51.737 |
The above table stores Temperature, Humidity likewise different parameters for the different countries at different times. I want an average of This parameter, max, min, last added value, and Last added Time for a specific day.
For example:
Parameters | Country | Average | Min | Max | Last value | Last updated time |
---|---|---|---|---|---|---|
Temperature | USA | 30 | 20 | 40 | 30 | 2021-09-04 12:09:51.737 |
Humidity | USA | 20 | 10 | 30 | 30 | 2021-09-04 12:09:51.737 |
This is what I did for Temperature
:
;WITH CTE AS
(
SELECT
AVG(Temperature) AVG_Temp,
MIN(Temperature) MIN_Temp,
MAX(Temperature) Max_Temp,
Country
FROM
Parameters_Log
GROUP BY
Country
WHERE
Country = 'USA'
AND CAST([date] AS date) = '2021-09-04'
)
First I am getting avg, Min, and Max for temperature for a country as above
SELECT TOP 1
c.Country,
c.AVG_Temp,
c.MIN_Temp,
c.Max_Temp,
[log].date,
[log].Temperature
FROM
Parameters_Log [log]
INNER JOIN
cte c ON c.country = [log].country
AND
WHERE
[log].Country = 'USA'
AND cast([log].[date] AS date) = '2021-09-04'
ORDER BY
[log].[date] DESC
Then I am using order by date desc to get the last added Temperature value and time. Finally, I am Taking Top 1 and store in a temporary table then the same procedure following for Humidity.
Can anyone guide me on what will be the performance-wise best approach?
Upvotes: 1
Views: 310
Reputation: 1269643
You can unpivot the values using apply
. Then use row_number()
and aggregation for the summary:
select country, parameter,
avg(val), min(val), max(val),
max(case when seqnum = 1 then val end) as last_val,
max(date)
from (select pl.country, pl.date, v.*,
row_number() over (partition by pl.country, v.parameter order by pl.date desc) as seqnum
from parameters_log pl cross apply
(values ('Temperature', pl.temperature), ('Humidity', pl.humidity)
) v(parameter, val)
) pl
group by country, parameter;
If you want a specific day, add a where
clause to the subquery, such as:
where pl.date >= '2021-09-04' and pl.date < '2021-09-05'
Here is a db<>fiddle.
Upvotes: 3
Reputation: 3467
Please try this. last value is picked based on max logid. apply cross join for whole result set into 2 copies.
-- SQL SERVER
SELECT CASE WHEN id = 1 THEN 'Temperature' ELSE 'Humidity' END Parameters
, pl.country
, CASE WHEN id = 1 THEN avg_temp ELSE avg_hum END Average
, CASE WHEN id = 1 THEN min_temp ELSE min_hum END "Min"
, CASE WHEN id = 1 THEN max_temp ELSE max_hum END "Max"
, CASE WHEN id = 1 THEN pl.temparature ELSE pl.humidity END last_value
, t.last_date "Last updated time"
FROM Parameters_Log pl
INNER JOIN (SELECT country
, MIN(temparature) min_temp
, MAX(temparature) max_temp
, AVG(temparature) avg_temp
, MIN(humidity) min_hum
, MAX(humidity) max_hum
, AVG(humidity) avg_hum
, MAX(logid) max_id
, MAX(tdate) last_date
FROM Parameters_Log
WHERE CAST(tdate AS date) = '2021-09-04'
GROUP BY country) t
ON pl.logid = t.max_id
CROSS JOIN (SELECT 1 id UNION SELECT 2 id) c
Please check from url https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=48e671202de62aeff8ea737ba4d1ba5a
If desired output depends on max_date then ON condition will
ON pl.tdate = t.last_date
If desired output depends on max log_id then ON condition will
ON pl.logid = t.max_id
Upvotes: 0