如何合并新记录而不再计算所有记录

时间:2017-06-22 15:33:27

标签: sql postgresql merge postgresql-9.4

我有一张有数百万行和数千辆汽车的汽车位置

SQL DEMO

ID  Car_ID  .... other fields
 1    A
 2    B
 3    B
 4    A
 5    A

我需要为每辆车创建路线。所以使用这个查询:

WITH cte as (
     SELECT ID, CAR_ID,
            ROW_NUMBER() OVER (PARTITION BY CAR_ID ORDER BY ID) as rn
     FROM myTable
)
SELECT o.CAR_ID, o.ID, d.ID
FROM cte as o       -- origin
LEFT JOIN cte as d  -- destination
  ON o.rn = d.rn - 1
 AND o."Car_ID" = d."Car_ID"
WHERE d.ID IS NOT NULL

我在route_sources

中插入路线
 ROUTE_SOURCE_id   CAR_ID    ORIGIN_ID   DESTINATION_ID
       1             A          1              4
       2             B          2              3
       3             A          4              5

问题是当输入新车位置时我需要检查已经创建的路线并将其添加到route_sources表。

例如新行

ID  Car_ID
 6    A
 7    B
 8    B

然后我只需要添加以下路线:

ROUTE_SOURCE_id   CAR_ID    ORIGIN_ID   DESTINATION_ID
       4             A          5              6
       5             B          3              7
       6             B          7              8

我知道如何进行合并,注意版本为9.4,因此INSERT ... ON CONFLICT UPDATE (and ON CONFLICT DO NOTHING), i.e. upsert.无法使用。

但我的问题是我不想每次只计算数百万条路线来添加新路线。

考虑car_position表获得大约6000条新记录。

我认为有两种选择:

  • car_positions表格中创建一个插入触发器,每次插入搜索前一个车位并创建路线并插入route_sources
  • 创建一个car_log表,我在其中保存用于为每辆汽车创建路线的最后一个ID,然后创建路线流程将检查比这些ID更新的ID。

但不是为每个插入做一个选择的粉丝,car_log的想法看起来太复杂了。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

http://rextester.com/NFTKN29525

不漂亮,但通常会创建一个CTE,您可以在其中查看每辆车的最后一个目的地,并将其与新车配对。在' B'的情况下,我们必须输入2条记录,查询的最后一个目的地没有更新,这就是为什么我必须让它从新数据中选择,如果可以的话。这种方法创建了一个记录,其中destination = origin,这就是我需要CTE的原因,我可以从中过滤出必要的内容。

为了遵守Stackoverflow规则,这里是查询本身:

WITH new_routes AS (
    SELECT DISTINCT
        n."Car_ID",
        greatest(first_value(r.destination_id) OVER (PARTITION BY r."Car_ID" ORDER BY r.destination_id DESC),
                 lag(n.destination_id, 1) OVER (PARTITION BY n."Car_ID" ORDER BY n.destination_id)) AS origin_id,
        n.destination_id
    FROM newData n
    JOIN result r ON r."Car_ID" = n."Car_ID" AND r.destination_id<n.destination_id
)
INSERT INTO result ("Car_ID", origin_id, destination_id)
SELECT * FROM new_routes WHERE origin_id<>destination_id
ORDER BY destination_id;

假设result是您之前的工作表,而newData是刚刚进入的新数据。

如果您有新车C,您可以使用以前为其创建路线的方法。使用plpgsql来控制这个决定。