最大和最小分组由2列

时间:2016-11-28 14:54:08

标签: sql sql-server group-by max

我有下表,每次有一辆车装满油箱时都会给我看。它返回日期,车辆ID,当时的里程数和填充的升数:

|   Date     | Vehicle_ID | Mileage | Liters |
| 2016-10-20 | 234        | 123456  | 100    |
| 2016-10-20 | 345        | 458456  | 215    |
| 2016-10-20 | 323        | 756456  | 265    |
| 2016-10-25 | 234        | 123800  | 32     |
| 2016-10-26 | 345        | 459000  | 15     |
| 2016-10-26 | 323        | 756796  | 46     |

这个想法是按月计算平均消费量(我不能白天做,因为不是每辆车每天都装满油箱。)

为此,我试图按月获得最大(里程)-min(里程)/总和(升)组。但这仅适用于1辆特定车型和1个特定月份。

如果我试用1辆特定车和几个月,最大值和最小值将无法正常返回。如果我添加所有的汽车,更糟糕的是,因为它将假设最大值和最小值,就好像每辆车都是相同的。

select convert(char(7), Date, 127) as year_month,
       sum("Liters tanked")/(max("Mileage")-min("Mileage"))*100 as Litres_per_100KM
from Tanking
where convert(varchar(10),"Date",23) >= DATEADD(mm, -5, GETDATE()) 
group by convert(char(7), Date, 127)

这不会起作用,因为它将假设所有车辆的最大值和最小值。

“工作流程”应该是这样的: - 每个月,获得每辆车的最大和最小里程。计算max-min以获得当月骑行的里程数。将每辆车的里程数相加,得到所有车辆的总里程数。将升数加起来。将总升数除以总里程数。

我如何得到结果:

| YearMonth | Average |
| 2016-06   |  30     |
| 2016-07   | 32      |
| 2016-08   | 46      |
| 2016-09   | 34      |

3 个答案:

答案 0 :(得分:1)

这是一个比看起来更复杂的问题。问题是你不想在几个月之间失去里程。做这样的事很有诱惑力:

select year(date), month(date),
       sum(liters) / (max(mileage) - min(mileage))
from Tanking
where Date >= dateadd(month, -5, getdate()) 
group by year(date), month(date);

但是,这会错过跨越月边界的英里和升。此外,本月第一个记录的升数是之前的 milage差异。哎呀!这是不正确的。

解决此问题的一种方法是查找下一个值。查询看起来像这样:

select year(date), month(date),
       sum(next_liters) / (max(next_mileage) - min(mileage))
from (select t.*,
             lead(date) over (partition by vehicle_id order by date) as next_date,
             lead(mileage) over (partition by vehicle_id order by date) as next_mileage,
             lead(liters) over (partition by vehicle_id order by date) as next_liters
      from Tanking t
     ) t
where Date >= dateadd(month, -5, getdate()) 
group by year(date), month(date);

这些查询使用简化的列名,因此转义字符不会干扰逻辑。

编辑:

哦,你有多辆车(可能是vehicle_Id所在的)。您需要两个级别的聚合。第一个查询看起来像:

select yyyy, mm, sum(liters) as liters, sum(mileage_diff) as mileage_diff,
       sum(mileage_diff) / sum(liters) as mileage_per_liter
from (select vehicle_id, year(date) as yyyy, month(date) as mm,
             sum(liters) as liters,
             (max(mileage) - min(mileage)) as mileage_diff
      from Tanking
      where Date >= dateadd(month, -5, getdate()) 
      group by vehicle_year(date), month(date)
     ) t
group by yyyy, mm;

第二个查询的类似更改(vehicle_id子句中的partition by)适用于第二个版本。

答案 1 :(得分:0)

尝试在子查询中获取每辆车每月的总和。然后使用子查询的值计算外部查询中的每月平均值:

select year_month,
       (1.0*sum(liters_per_car)/sum(mileage_per_car))*100.0 as Litres_per_100KM
from (
   select convert(char(7), [Date], 127) as year_month,       
          sum(Liters) as liters_per_car,
          max(Mileage)-min(Mileage) as mileage_per_car       
   from Tanking
   group by convert(char(7), [Date], 127), Vehicle_ID) as t
group by year_month

答案 2 :(得分:0)

您可以使用CTE获得dif(里程),然后计算消耗量:

可在此处查看:http://rextester.com/OKZO55169

with cte (car, datec, difm, liters)
as 
(
select 
    car, 
    datec, 
    mileage - lag(mileage,1,mileage) over(partition by car order by car, mileage) as difm, 
    liters 
from #consum 
) 
select 
    car, 
    year(datec) as [year], 
    month(datec) as [month], 
    ((cast(sum(liters) as float)/cast(sum(difm) as float)) * 100.0) as [l_100km]
from 
    cte
group by 
    car, year(datec), month(datec)