0

我正在尝试调整路线管理。

我们有与邮政编码范围相关的路线代码。它们用于在交付订单时选择正确的运输路线。

一条路线将具有其活动的邮政编码范围,并且可能有一个客户端——如果该路线仅针对该客户端。

因此,路由表如下所示:

       route_no        | zipfrom | zipto |  client
-----------------------+---------+-------+----------
 ROUTE-CLIENTA-SPECIAL | 12330   | 12350 | CLIENT-A
 ROUTE-CLB1            | 33331   | 44445 | CLIENT-B
 ROUTE-SCENIC          | 11111   | 99999 |
(3 rows)

所以,根据这张表:

  • 每个订单都必须经过 ROUTE-SCENIC,包括客户 CLIENT-A 和 CLIENT-B。
  • 除非订单是针对 CLIENT-A 的并且交付是针对邮政编码在 12330-12350 之间的地址——这些通过 ROUTE-CLIENTA-SPECIAL 进行。
  • 或者它是 CLIENT-B 的订单,并且订单的邮政编码在 33331 和 44445 之间——然后它转到路由 ROUTE-CLB1

所以,对于今天的订单:

 order_id |  client  | route_no |  zip
----------+----------+----------+-------
 123      | CLIENT-A |          | 12345
 124      | CLIENT-A |          | 33333
 125      | CLIENT-A |          |
 N988     | CLIENT-B |          | 77777
 N987     | CLIENT-B |          | 33335
 N0981    | CLIENT-B |          | 44444
 N0983    | CLIENT-B |          | 12345

要获得 CLIENT-B 订单 N987 的可能路线(邮政编码 33333),我可以这样做:

SELECT client,route_no FROM routes 
WHERE (client='CLIENT-B' OR client IS NULL )  
   AND '33333' BETWEEN zipfrom AND zipto ORDER BY client;

  client  |   route_no
----------+--------------
 CLIENT-B | ROUTE-CLB1
          | ROUTE-SCENIC
(2 rows)

在这个 ROUTE-CLB1 之外是正确的路由(它比默认路由更具体到客户端)。

我可以通过 ORDER BY 和 LIMIT 1 始终选择正确的路线。

但我需要用正确的路线更新订单表。我可以用子查询来做到这一点:

UPDATE orders AS O 
   SET route_no=(SELECT R.route_no FROM routes R
              WHERE (O.client=R.client OR R.client IS NULL )
                    AND O.zip BETWEEN R.zipfrom AND R.zipto 
              ORDER BY R.client LIMIT 1);

这给出了正确的答案:

  id   |  client  |         route_no      |  zip
-------+----------+-----------------------+-------
 123   | CLIENT-A | ROUTE-CLIENTA-SPECIAL | 12345
 124   | CLIENT-A | ROUTE-SCENIC          | 33333
 125   | CLIENT-A |                       |
 N988  | CLIENT-B | ROUTE-SCENIC          | 77777
 N987  | CLIENT-B | ROUTE-CLB1            | 33335
 N0981 | CLIENT-B | ROUTE-CLB1            | 44444
 N0983 | CLIENT-B | ROUTE-SCENIC          | 12345
(7 rows)

但这在较大的订单列表上往往非常慢,因为子查询针对每一行运行。

我该如何改进它?我尝试按照在每个 GROUP BY 组中选择第一行中的描述使用 DISTINCT ON ?但这似乎不起作用。

4

1 回答 1

1

您可能会发现使用正确的索引会更快:

UPDATE orders o
   SET route_no = COALESCE( (SELECT R.route_no
                             FROM routes R
                             WHERE O.client = R.client AND
                                   O.zip BETWEEN R.zipfrom AND R.zipto 
                             LIMIT 1
                            ), 
                            (SELECT R.route_no
                             FROM routes R
                             WHERE R.client IS NULL AND
                                   O.zip BETWEEN R.zipfrom AND R.zipto 
                             LIMIT 1
                            )
                           );

然后你想要一个关于routes(client, zipfrom, zipto). 索引至少会在routes不扫描表的情况下快速找到候选行。Postgres 可能会用 来解决这个问题or,但这值得一试。

于 2021-04-30T11:18:14.787 回答