【问题标题】:What is the SQL query to calculate average lease time?计算平均租用时间的 SQL 查询是什么?
【发布时间】:2019-05-31 11:15:40
【问题描述】:

我需要计算按品牌分组的汽车的平均租赁时间。

为简单起见,我的数据库中有以下LEASE 表:

carMake | startDateTime | endDateTime

我未完成的 SQL 查询如下所示:

SELECT lease.carMake 
FROM lease
WHERE lease.startDateTime <= {?endDate} AND lease.endDateTime >= {?startDate}
SUM ... ???
GROUP BY lease.carMake ;

例子:

carMake |   startDateTime   | endDateTime
MB        01.01.2018 00:00     01.01.2019 00:00
BMW       07.06.2018 21:00     01.01.2019 00:00
MB        06.06.2018 00:00     07.06.2018 00:00 

查询范围在 06.06.2018 和 07.06.2018 之间的结果:

carMake | avgTime
MB        36 hours
BMW       3 hours

数据库是 PostgreSQL

【问题讨论】:

  • 请提供样本数据、所需结果以及您正在使用的数据库的标签。
  • 什么是 36 和 3?几天或几个月还是什么?
  • 小时,BMW是21:00开始租的,因为只重叠了3个小时
  • 您不会求和,而是平均(平均)天*24+24 的差异。您如何做到这一点因供应商而异。您的语法不知道您的后端是什么。以postgreSQL为例:select carMake, avg(extract(epoch from (endDate-startDate))/3600 + 24) as hours from leases group by carMake;
  • 嗨 Cetin,我使用的是 PostgreSQL,只是找不到标签。 avg(extract(epoch from (endDate-startDate))/3600 + 24) 而且我还必须考虑每辆车的 Math.max(startDateTime when car is Rented, startDate Query) 和 endDateTime 相同

标签: sql postgresql date datetime


【解决方案1】:

我不确定您使用的是什么 sql,但在 SQL Server 中您可以执行类似的操作

DECLARE @startdate DATETIME= '2018-06-06 00:00:00'
DECLARE @endDate DATETIME= '2018-06-07 00:00:00'


SELECT LeaseTable.CarMake, AVG(LeaseTable.LeaseHours)
FROM
(SELECT lease.carmake, 
    DATEDIFF(HH, case when lease.startDate <@startdate then @startdate else lease.startDate end, dateadd(DD, 1 ,case when lease.endDate > @endDate then @endDate else lease.endDate end)) as LeaseHours
    FROM lease
where 
    lease.startDate <= @endDate AND lease.endDate >= @startdate) as LeaseTable
GROUP BY LeaseTable.carMake 

让我分解一下:

SELECT carmake, AVG(LeaseHours) -- know the lease time avr by car manufacture
FROM
(Select
    LeaseInPeriod.carmake, 
    DATEDIFF(HH, LeaseInPeriod.PeriodStartDate, LeaseInPeriod.PeriodEndDate) as LeaseHours -- Know the lease time in hour
FROM
(SELECT lease.carmake, 
    case when lease.startDate <@startdate then @startdate else lease.startDate end as PeriodStartDate, -- Know the actual lease start date between the perid limits
    dateadd(DD, 1 ,case when lease.endDate > @endDate then @endDate else lease.endDate end) as PeriodEndDate -- Know the actual lease end date between the perid limits
    FROM AS lease
where 
    lease.startDate <= @endDate AND lease.endDate >= @startdate) AS LeaseInPeriod
) Leases
GROUP BY Leases.carMake 

【讨论】:

【解决方案2】:

这可以很容易地用timestamp range 解决。

首先我们计算所需时间和租用时间之间的重叠间隔,从中我们可以计算以小时为单位的平均值:

select carmake, avg(extract(epoch from upper(duration) - lower(duration)) / 3600) as hours
from (
  select carmake, 
         tsrange(startdatetime, enddatetime, '[]') * tsrange(timestamp '2018-06-06 00:00:00', timestamp '2018-06-08 00:00:00', '[)') duration
  from lease
) t
group by carmake;

诀窍是 tsrange 的交集运算符 *

在线示例:https://rextester.com/KYXB18998

【讨论】:

  • 如果我有不同的区域,然后时间戳不适合怎么办
  • 那么您应该使用timestamp with time zone 而不是timestamp - 但是您应该在原始问题中包含该重要信息(并且您接受的答案也不会处理该问题,除非您使用带时区的时间戳)
  • 为什么?我需要根据位置的时间进行查询,而不是根据时间轴中的某个点
  • 那么您说的是哪些“位置”?您的问题中没有关于“位置”的内容。
【解决方案3】:
SELECT carMake, AVG(endDateTime - startDateTime) AS avgTime WHERE startDateTime <= {?endDate} AND endDateTime >= {?startDate} FROM lease GROUP BY 1;

【讨论】:

  • 我还必须考虑每辆车的 Math.max(startDateTime when car is Rented, startDate Query) 和 endDateTime 相同,为什么 GROUP BY 1?
  • endDateTime - startDateTime 是租约的持续时间(结束和开始之间的时间段)。因此查询准确计算按品牌分组的平均持续时间(GROUP BY 1 是第一列分组的缩写)。
  • 如果租期超出查询范围怎么办?
  • 如果租期超出范围边界,将被WHERE条件过滤掉,不会用于平均计算。
  • 我的意思是,可以从 01.01.2018 到 12.12.2018 租车,我查询从 06.06.2018 到 07.06.2018 -> endDate - startDate 应该等于 2 天。如果从 06.06.2018 00:00 到 07.06.2018 00:00 租车,则 endDate - startDate 等于 1 天
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-25
  • 1970-01-01
  • 1970-01-01
  • 2020-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多