Reputation: 35
I've a situation, where I need to get both min() and max() of column and one more column that corresponds to min() and max() functions. I've tried the query using INNER JOIN, it was successful when using either min() or max(). When both are used nothing returned.
SELECT A.IslandCode, CONVERT(DATE, A.LogTime)LogTime
, MN.Demand MinDemand, MN.TIME MinDemandAt
FROM
(
SELECT IslandCode, CONVERT(DATE, LogTime) LogTime, SUM(KiloWatt) Demand
FROM ph_MachineDailyReadings
WHERE IslandCode = 1 AND CONVERT(DATE, LogTime) = '2013-08-13'
GROUP BY IslandCode, LogTime
) A
INNER JOIN
(
SELECT TOP 1 IslandCode, CONVERT(DATE, LogTime) LogTime, SUM(KiloWatt) Demand,
STR(DATEPART(HOUR, LogTime)) + ':' + LTRIM(STR(DATEPART(MINUTE, LogTime))) TIME
FROM ph_MachineDailyReadings
WHERE IslandCode = 1 AND CONVERT(DATE, LogTime) = '2013-08-13'
GROUP BY IslandCode, LogTime
ORDER BY Demand
) MN
ON A.IslandCode = MN.IslandCode AND A.LogTime = MN.LogTime AND A.Demand = MN.Demand
the above query returns following result, that is correct
IslandCode LogTime MinDemand MinDemandAt
1 2013-08-13 698 13:0
query for max()
SELECT A.IslandCode, CONVERT(DATE, A.LogTime)LogTime
, MX.Demand MaxDemand, MX.TIME MaxDemandAt
FROM
(
SELECT IslandCode, CONVERT(DATE, LogTime) LogTime, SUM(KiloWatt) Demand
FROM ph_MachineDailyReadings
WHERE IslandCode = 1 AND CONVERT(DATE, LogTime) = '2013-08-13'
GROUP BY IslandCode, LogTime
) A
INNER JOIN
(
SELECT TOP 1 IslandCode, CONVERT(DATE, LogTime) LogTime, SUM(KiloWatt) Demand,
STR(DATEPART(HOUR, LogTime)) + ':' + LTRIM(STR(DATEPART(MINUTE, LogTime))) TIME
FROM ph_MachineDailyReadings
WHERE IslandCode = 1 AND CONVERT(DATE, LogTime) = '2013-08-13'
GROUP BY IslandCode, LogTime
ORDER BY Demand DESC
) MX
ON A.IslandCode = MX.IslandCode AND A.LogTime = MX.LogTime AND A.Demand = MX.Demand
returns, this is also correct
IslandCode LogTime MaxDemand MaxDemandAt
1 2013-08-13 1463 20:0
but when both the queries are used in same query, returns nothing
SELECT A.IslandCode, CONVERT(DATE, A.LogTime)LogTime
, MX.Demand MaxDemand, MX.TIME MaxDemandAt
, MN.Demand MinDemand, MN.TIME MinDemandAt
FROM
(
SELECT IslandCode, CONVERT(DATE, LogTime) LogTime, SUM(KiloWatt) Demand
FROM ph_MachineDailyReadings
WHERE IslandCode = 1 AND CONVERT(DATE, LogTime) = '2013-08-13'
GROUP BY IslandCode, LogTime
) A
INNER JOIN
(
SELECT TOP 1 IslandCode, CONVERT(DATE, LogTime) LogTime, SUM(KiloWatt) Demand,
STR(DATEPART(HOUR, LogTime)) + ':' + LTRIM(STR(DATEPART(MINUTE, LogTime))) TIME
FROM ph_MachineDailyReadings
WHERE IslandCode = 1 AND CONVERT(DATE, LogTime) = '2013-08-13'
GROUP BY IslandCode, LogTime
ORDER BY Demand DESC
) MX
ON A.IslandCode = MX.IslandCode AND A.LogTime = MX.LogTime AND A.Demand = MX.Demand
INNER JOIN
(
SELECT TOP 1 IslandCode, CONVERT(DATE, LogTime) LogTime, SUM(KiloWatt) Demand,
STR(DATEPART(HOUR, LogTime)) + ':' + LTRIM(STR(DATEPART(MINUTE, LogTime))) TIME
FROM ph_MachineDailyReadings
WHERE IslandCode = 1 AND CONVERT(DATE, LogTime) = '2013-08-13'
GROUP BY IslandCode, LogTime
ORDER BY Demand
) MN
ON A.IslandCode = MN.IslandCode AND A.LogTime = MN.LogTime AND A.Demand = MN.Demand
expected result
IslandCode LogTime MinDemand MinDemandAt MaxDemand MaxDemandAt
1 2013-08-13 1463 20:0 698 13:0
can i get this result in single query or do i need to go for a stored procedure based solution?
thanks in advance
Upvotes: 2
Views: 4593
Reputation: 69759
You can do this using Analytic functions:
WITH Data AS
( SELECT IslandCode,
LogDate = CAST(LogTime AS DATE),
LogTime,
Demand = SUM(KiloWatt) ,
RowNumAsc = ROW_NUMBER() OVER (PARTITION BY IslandCode, CAST(LogTime AS DATE) ORDER BY SUM(Kilowatt)),
RowNumDesc = ROW_NUMBER() OVER (PARTITION BY IslandCode, CAST(LogTime AS DATE) ORDER BY SUM(Kilowatt) DESC)
FROM ph_MachineDailyReadings
WHERE IslandCode = 1
AND CAST(LogTime AS DATE) = '20130813'
GROUP BY IslandCode, LogTime
)
SELECT ma.IslandCode,
LogTime = ma.LogDate,
MinDemand = mi.Demand,
MinDemandAt = CAST(mi.LogTime AS TIME),
MaxDemand = ma.Demand,
MaxDemandAt = CAST(ma.LogTime AS TIME)
FROM Data mi
INNER JOIN Data ma
ON ma.IslandCode = mi.IslandCode
AND ma.LogDate = mi.LogDate
WHERE mi.RowNumAsc = 1
AND ma.RowNumDesc = 1;
EDIT
This does not require parameters, and if the WHERE
clause is omitted as follows it would return the min and max for each island code on each date:
WITH Data AS
( SELECT IslandCode,
LogDate = CAST(LogTime AS DATE),
LogTime,
Demand = SUM(KiloWatt) ,
RowNumAsc = ROW_NUMBER() OVER (PARTITION BY IslandCode, CAST(LogTime AS DATE) ORDER BY SUM(Kilowatt)),
RowNumDesc = ROW_NUMBER() OVER (PARTITION BY IslandCode, CAST(LogTime AS DATE) ORDER BY SUM(Kilowatt) DESC)
FROM ph_MachineDailyReadings
GROUP BY IslandCode, LogTime
)
SELECT ma.IslandCode,
LogTime = ma.LogDate,
MinDemand = mi.Demand,
MinDemandAt = CAST(mi.LogTime AS TIME),
MaxDemand = ma.Demand,
MaxDemandAt = CAST(ma.LogTime AS TIME)
FROM Data mi
INNER JOIN Data ma
ON ma.IslandCode = mi.IslandCode
AND ma.LogDate = mi.LogDate
WHERE mi.RowNumAsc = 1
AND ma.RowNumDesc = 1;
One final note, I have put your logTime in the TIME format as this seems more usable than a VARCHAR Format, if you do need it in VARCHAR you can use:
CONVERT(VARCHAR(10), ma.LogTime, 8)
Upvotes: 2
Reputation: 1269643
I don't think you need the second join. You could do this with just a union all
:
(SELECT TOP 1 IslandCode, CONVERT(DATE, LogTime) LogTime, SUM(KiloWatt) Demand,
STR(DATEPART(HOUR, LogTime)) + ':' + LTRIM(STR(DATEPART(MINUTE, LogTime))) TIME
FROM ph_MachineDailyReadings
WHERE IslandCode = 1 AND CONVERT(DATE, LogTime) = '2013-08-13'
GROUP BY IslandCode, LogTime
ORDER BY Demand
) union all
(SELECT TOP 1 IslandCode, CONVERT(DATE, LogTime) LogTime, SUM(KiloWatt) Demand,
STR(DATEPART(HOUR, LogTime)) + ':' + LTRIM(STR(DATEPART(MINUTE, LogTime))) TIME
FROM ph_MachineDailyReadings
WHERE IslandCode = 1 AND CONVERT(DATE, LogTime) = '2013-08-13'
GROUP BY IslandCode, LogTime
ORDER BY Demand desc
)
Upvotes: 0