PostgreSQL 连接两个值

PostgreSQL Joining Between Two Values

我有以下 table 并且正在尝试查找县代码以获得数十万个城市的列表。

create table counties (
  zip_code_from  char(5) not null,
  zip_code_thru  char(5) not null,
  county_code    char(3) not null
);

create table cities (
  city      text    not null,
  zip_code  char(5) not null
);

我的第一种方法是在连接中使用 "between":

select
  ci.city, ci.zip_code, co.county_code
from
  cities ci
  join counties co on
    co.zip_code between ci.zip_code_from and ci.zip_code_thru

我知道在 Oracle 的世界里,这是不受欢迎的,而且确实表现得很糟糕。处理大约 16,000 个城市需要 8 多分钟。邮政编码 table 有大约 80,000 条记录。我猜这个语法是美化的交叉连接?

来自和通过代码都已编入索引,我可以控制结构,因此如果有帮助,我可以更改 table。

我唯一的其他想法是继续将 table 扩展到所有可能的值——类似于此:

select
  generate_series (
    cast (zip_code_from as int),
    cast (zip_code_thru as int)
  ) as zip_code,
  *
from counties

这会将数据扩展到超过 200,000 条记录,这不是什么大问题,但我不确定这是否是我获得不可怕查询的唯一途径。

我猜即使是在运行中执行此操作并且没有索引也比我的连接中的 between 更可取,但我希望有一个替代方案,无论是就我的 SQL and/or 我可以用 table 本身的结构做一些事情。

我已经看到针对其他 DBMS 平台发布的这个问题,但我已经能够使用 PostgreSQL 实现在其他数据库中不可能(或不实用)的迷你奇迹,所以我希望我错过了什么。

几个月后,它又出现了,我决定检验我的一些理论。

原查询:

select
  ci.city, ci.zip_code, co.fips_code
from
  cities ci
  join counties co on
    ci.zip_code between co.from_zip_code and co.thru_zip_code

确实实现了笛卡尔。查询 returns 34,000 行,耗时 597 秒。

如果我 "pre-explode" 将邮政编码范围分成离散记录:

with exploded_zip as (
  select
    generate_series (
      cast (from_zip_code as int),
      cast (thru_zip_code as int)
    )::text as zip_code,
    *
  from counties
)
select
  ci.city, ci.zip_code, co.fips_code
from
  cities ci
  join exploded_zip co on
    ci.zip_code = co.zip_code

查询 returns 完全相同的行,但在 2.8 秒内完成。

所以底线似乎是在连接(或任何不等式)中使用 between 是一个非常糟糕的主意。