【问题标题】:Calculate time spend in countries计算在国家/地区花费的时间
【发布时间】:2021-07-13 12:43:23
【问题描述】:

我正在尝试寻找一种方法来检测各国在汽车上花费的时间。

这是我的表格,用于跟踪记录的存储时间/方式:

car_id, seen,      country

001     2021-02-03 germany
001     2021-02-21 germany
001     2021-03-02 germany
001     2021-03-10 france
001     2021-03-21 germany
003 ...

输出的想法可能在以下领域:

car_id, seen,      country, interval_in_same_country

001     2021-02-03 germany  0 days
001     2021-02-21 germany  18 days  
001     2021-03-02 germany  27 days
001     2021-03-10 france   0 days
001     2021-03-21 germany  0 days
003 ...

也许有更好的办法,但这是我最初的想法。 有关如何进行此类计算的任何帮助?

【问题讨论】:

  • 与您的问题无关,但是:Postgres 9.4 是no longer supported,您应该尽快计划升级。
  • 这些0 days是什么意思?我猜你想要国家=法国的行“11天”。
  • 不,我们第一次看到france2021-03-10。我们不知道它之前是在德国还是刚刚进入法国。
  • 根据什么逻辑得到27,其余的0?
  • 这同样适用于任何行。你怎么知道这辆车在德国已经18天了?您的要求不明确。

标签: sql postgresql postgresql-9.4


【解决方案1】:

使用窗口函数lag()sum()

WITH j AS (
  SELECT DISTINCT ON (car_id,seen,country) *, 
    coalesce(CASE 
               WHEN LAG(country) OVER (ORDER BY seen) <> country THEN 0
             ELSE 
               seen-LAG(seen) OVER (PARTITION BY car_id,country ORDER BY seen )
             END,0) AS days
  FROM t 
  ORDER BY seen ASC)
SELECT car_id,seen,country,
  CASE WHEN days <> 0 AND LAG(days) OVER w <> 0 THEN
    sum(days) OVER w
  ELSE days
  END interval_in_same_country
FROM j 
WINDOW w AS (PARTITION BY car_id,country ORDER BY seen ASC)
ORDER BY seen ;

演示:db&lt;&gt;fiddle

【讨论】:

  • 获取Query 1 ERROR: ERROR: CASE types interval and integer cannot be matched LINE 4: 0
  • @AlfredBalle 你检查过小提琴吗?另外,你能用导致错误的数据修改这个小提琴并将链接发送给我们吗?
  • 似乎在小提琴演示中工作。唯一的问题是小提琴分别显示德国 18 天和 9 天,而 9 天的应该合并为 18+9=27 天 - 否则真的很好:)
  • @AlfredBalle 也许这可能会有所帮助:dbfiddle.uk/…
  • 看起来很漂亮,很棒。谢谢你:)
【解决方案2】:

你可以使用滞后窗口功能

select 
  car_id,
  seen,
  country,
  case 
    when interval_in_same_country < 0 then (interval_in_same_country * (-1))
    when interval_in_same_country is null then 0
    else interval_in_same_country
  end as interval_in_same_country
from
  (select * ,
      case 
        when lag(country) over (order by seen) <> country then 0
        else DATE_PART('day', seen::timestamp) - DATE_PART('day', lag(seen,1) over(order by car_id)::timestamp)
        end as interval_in_same_country

   from table) t

【讨论】:

  • 我收到了错误column "day" does not exist
  • 我在答案中加入了适当的 PostgreSQL 9.0 代码。您的问题不清楚,但在答案中,它将每一行的记录与上一行的记录进行比较,并显示在输出中。
【解决方案3】:

您可以将lag() 与三个参数和一些条件逻辑一起使用:

select t.*,
       (case when lag(country) over (order by car_id) = country
             then seen - lag(seen, 1, seen) over (order by car_id)
             else interval '0 day'
        end) 
from t;

【讨论】:

  • 收到错误ERROR: CASE types integer and interval cannot be matched - ERROR seen - lag(seen, 1, seen) over (order by car_id)
  • @AlfredBalle 。 . .我认为这是由于默认条件。不过,看起来很奇怪。 seen 是什么数据类型?在你的问题中看起来像一个日期,上面应该可以正常工作。但是,如果它是一个时间戳,那么您需要一个明确的 interval,正如这个 dbfiddle 所示:dbfiddle.uk/…
猜你喜欢
  • 2013-06-12
  • 1970-01-01
  • 1970-01-01
  • 2022-11-14
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 2014-11-22
  • 2019-09-28
相关资源
最近更新 更多