【问题标题】:PostgreSql Having conflict between group by and needing to add two more columnsPostgreSql group by 之间存在冲突,需要再添加两列
【发布时间】:2015-01-05 15:43:32
【问题描述】:

问题:

找到完全被一个国家包围的内陆国家。报告身份证 和内陆国家的名称,然后是其周围国家的 ID 和名称。

输出表:Query3

属性:

  c1id (landlocked country id) [INTEGER]
  c1name (landlocked country name) [VARCHAR(20)]
  c2id (surrounding country id) [INTEGER]
  c2name (surrounding country name) [VARCHAR(20)]

Order by: c1name ASC

架构:

  • 国家表包含世界上所有国家及其事实。
  • 'cid' 是国家的 id。
  • 'name' 是国家/地区的名称。
  • 'height' 是该国的最高海拔点。
  • “人口”是该国的人口。

    CREATE TABLE country (
        cid         INTEGER     PRIMARY KEY,
        cname       VARCHAR(20) NOT NULL,
        height      INTEGER     NOT NULL,
        population  INTEGER     NOT NULL);
    
  • 邻居表提供有关国家及其邻国的信息。

  • 'country' 指第一个国家的cid。

  • 'neighbor'是指与第一个国家相邻的国家的cid。
  • 'length'是两个邻国边界的长度。

请注意,如果 A 和 B 是邻居,则表中存储了两个元组来表示该信息 (A, B) 和 (B, A)。

CREATE TABLE neighbour (
country     INTEGER     REFERENCES country(cid) ON DELETE RESTRICT,
neighbor    INTEGER     REFERENCES country(cid) ON DELETE RESTRICT, 
length      INTEGER     NOT NULL,
PRIMARY KEY(country, neighbor));

我的尝试:

这是我的原始查询,它获取只有一个邻居的所有国家/地区的名称和 cid

SELECT c.cid   AS c1id,
       c.cname AS c1name
FROM   country c
       JOIN neighbour n
         ON n.country = c.cid
GROUP  BY c.cid,
          c.cname
HAVING Count(n.neighbor) = 1; 

问题是我还需要邻国的名称和国家/地区 ID,所以我尝试这样做:

SELECT c.cid   AS c1id,
       c.cname AS c1name,
       n.neighbor,
       c2.cname
FROM   country c
       JOIN neighbour n
         ON n.country = c.cid
       JOIN country c2
         ON n.neighbor = c2.cid
GROUP  BY c.cid,
          c.cname
HAVING Count(n.neighbor) = 1; 

问题显然源于 n.neighbour 和 c2.cname 不在 group by 子句中。如果我确实将它们添加到 group by 子句中,那么即使一个国家有多个邻居,count(n.neighbor) 也会分别计算每个国家的邻居。

例如,如果希腊 (cid = 1) 与土耳其 (cid = 2) 和德国 (cid = 3) 相邻。加拿大 (cid = 4) 与美国 (cid = 5) 相邻,那么第二个查询的输出将是

1 希腊 2 土耳其 1 希腊 3 德国 4 加拿大 5 美国

而不是

4 加拿大 5 美国

我该如何解决这个问题?

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    我认为最简单的方法是

    • 解析“neighbour”所需的连接,然后
    • 将您的第一个查询加入到结果中。

    样本数据

    感谢您在问题中包含 CREATE TABLE 语句。

    insert into country values
    (1, 'Greece', 1, 1), (2, 'Turkey', 1, 1), (3, 'Germany', 1, 1), 
    (4, 'Canada', 1, 1), (5, 'USA', 1, 1);
    
    insert into neighbour values
    (1, 2, 1), (2, 1, 1), (1, 3, 1), (3, 1, 1), 
    (4, 5, 1), (5, 4, 1);
    

    解决连接问题

    select c1.cid , c1.cname as cname, c2.cid as nid, c2.cname as nname 
    from neighbour n
    inner join country c1 on c1.cid = n.country
    inner join country c2 on c2.cid = n.neighbor;
    

    加入您的第一个查询

    前四行与上面的查询相同。

    select c1.cid , c1.cname as cname, c2.cid as nid, c2.cname as nname 
    from neighbour n
    inner join country c1 on c1.cid = n.country
    inner join country c2 on c2.cid = n.neighbor
    inner join (SELECT c.cid   AS c1id,
                       c.cname AS c1name
                FROM   country c
                JOIN neighbour n
                  ON n.country = c.cid
                GROUP  BY c.cid, c.cname
                HAVING Count(n.neighbor) = 1) n2
    on c1.cid = n2.c1id;
    

    上述查询中的最终连接保证第一对列中的国家/地区有一个邻居。

    cid cname nid nname -- 2 土耳其 1 希腊 3 德国 1 希腊 4 加拿大 5 美国 5 美国 4 加拿大

    【讨论】:

    • 哇,非常感谢!你解释的很清楚!
    猜你喜欢
    • 1970-01-01
    • 2020-02-08
    • 1970-01-01
    • 2020-04-16
    • 2021-11-18
    • 2011-02-11
    • 2018-07-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多