连接表,但确保返回第一个表中的所有行

时间:2020-08-02 19:12:13

标签: sql postgresql

我有一个用于在PostgreSQL中存储邮政信息的系统。我们有一个postal_carriers表,其中详细列出了运营商信息。我们有一个postal_zones表,其中包含postal_carriers的区域。我们有一个countries表,其中包含国家/地区信息。现在,我创建了一个postal_zone_mapping表,该表将国家/地区映射到不同运营商的区域。这是它的定义。

CREATE TABLE shopman.postal_zone_mapping
(
    postal_zone_id integer,
    postal_carrier_id integer,
    country_id integer,
    CONSTRAINT pzm_key UNIQUE (country_id, postal_carrier_id),
    CONSTRAINT pzm_fkey FOREIGN KEY (country_id)
        REFERENCES shopman.countries (country_id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION,
    CONSTRAINT postal_zone_mapping_postal_carrier_id_fkey FOREIGN KEY (postal_carrier_id)
        REFERENCES shopman.postal_carriers (postal_carrier_id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION,
    CONSTRAINT postal_zone_mapping_postal_zone_id_fkey FOREIGN KEY (postal_zone_id)
        REFERENCES shopman.postal_zones (postal_zone_id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)

这是我用来选择数据的语句,选择country表上带有左连接的postal_zone_mapping表,因为我希望列出所有承运商所在的国家/地区,无论它们是重新映射到特定的载波和区域。

    SELECT c.country_id,
           COALESCE(postal_zone_id,-1) AS postal_zone_id,
           COALESCE(postal_carrier_id,-1) AS postal_carrier_id,
           country_name
      FROM shopman.countries c 
           LEFT JOIN shopman.postal_zone_mapping p 
                  ON c.country_id=p.country_id
     WHERE postal_carrier_id=1 
        OR postal_carrier_id IS NULL 
     ORDER BY country_name ASC 
    OFFSET 0 ROWS FETCH FIRST 50 ROWS ONLY

我希望此查询返回每个国家/地区,如果运营商ID与我们想要的国家/地区ID匹配,则返回运营商ID,但是对于我的查询,如果我们为运营商插入地图,则返回的结果不包含该国家/地区。我的查询哪里出问题了?另外,是否有更好的方法来实现此映射?我走了这条路,以避免必须动态添加列或拥有数组。

非常感谢

作为参考,以下是其他表的定义:

CREATE TABLE shopman.postal_carriers
(
    postal_carrier_id serial,
    postal_carrier_name text,
    description text,
    CONSTRAINT postal_carriers_pkey PRIMARY KEY (postal_carrier_id),
    CONSTRAINT postal_carriers_postal_carrier_name_key UNIQUE (postal_carrier_name)
)

CREATE TABLE shopman.postal_zones
(
    postal_zone_id serial,
    postal_carrier_id integer,
    postal_zone_name text,
    CONSTRAINT postal_zones_pkey PRIMARY KEY (postal_zone_id),
    CONSTRAINT postal_zones_postal_zones_name_key UNIQUE (postal_carrier_id, postal_zone_name),
    CONSTRAINT postal_zones_postal_carrier_id_fkey FOREIGN KEY (postal_carrier_id)
        REFERENCES shopman.postal_carriers (postal_carrier_id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)

CREATE TABLE shopman.countries
(
    country_id serial,
    country_name text,
    code_2 text",
    code_3 text,
    region_id integer,
    CONSTRAINT countries_pkey PRIMARY KEY (country_id),
    CONSTRAINT countries_code_2_key UNIQUE (code_2),
    CONSTRAINT countries_code_3_key UNIQUE (code_3),
    CONSTRAINT countries_name_key UNIQUE (country_name),
    CONSTRAINT countries_region_id_fkey FOREIGN KEY (region_id)
        REFERENCES shopman.regions (region_id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)

1 个答案:

答案 0 :(得分:3)

second 表上的条件移到ON子句中:

SELECT c.country_id,
       COALESCE(p.postal_zone_id, -1) AS postal_zone_id,
       COALESCE(p.postal_carrier_id,-1) AS postal_carrier_id,
       c.country_name
FROM shopman.countries c LEFT JOIN
     shopman.postal_zone_mapping p 
     ON c.country_id = p.country_id AND p.postal_carrier_id = 1 
ORDER BY c.country_name ASC 
OFFSET 0 ROWS FETCH FIRST 50 ROWS ONLY