2013-03-12 118 views
0

目标是使用两个不同的表进行查询;国家和城市。国家包含国家名称和国家代码(主键),城市包含城市名称,人口和国家代码(主键)。我想使用聚合函数GROUP BY,但下面的查询不起作用。如何在postgresql中使用group by

对于每个国家,列出其所有城市的最大人口和该城市的名称。 所以我需要列出每个国家人口最多的城市。

所以应该显示的是国家,城市(人口最多),然后是该城市的人口。每个城市只能有一个国家。

$query6 = "SELECT c.name AS country, ci.name AS city, 
GREATEST(ci.population) AS max_pop 
FROM lab6.country c INNER JOIN lab6.city ci 
ON(c.country_code = ci.country_code) 
GROUP BY c.name 
ORDER BY country ASC"; 

我也试过GROUP BY国家,DISTINCT c.name。

我是新来的聚合函数,所以如果有特定的情况,你应该使用GROUP BY,这不是其中之一,请让我知道。

我使用PHP来运行,像这样的查询:

$result = pg_query($connection, $query); 
if(!$result) 
{ 
     die("Failed to connect to database"); 
} 

错误:列“ci.name”必须出现在GROUP BY子句或聚合函数LINE 1使用:选择不同的C- .name AS国家,ci.name AS城市,是错误。

表格给我们,我们不制作它们,也不能包含制作表格的屏幕截图,因为我没有任何声望。

+0

为表格发布SQL DDL而不是描述它们要好得多。 – 2013-03-12 01:10:05

+0

它为什么不起作用,它返回的是什么错误? – Farlan 2013-03-12 01:16:00

+0

对不起,什么是SQL DDL。这是我在我的实验室遇到的我的数据库类遇到的问题。如果你让我知道它是什么,我会尝试发布,而不是。 – Paigentry 2013-03-12 01:16:43

回答

2

一些DDL可以玩。

create table country (
    country_code char(2) primary key, -- ISO country code 
    country_name varchar(35) not null unique 
); 

insert into country values 
('US', 'United States of America'), 
('IT', 'Italy'), 
('IN', 'India'); 

-- The full name of a city is more than city name plus country name. 
-- In the US, there are a couple of dozen cities named Springfield, 
-- each in a different state. I'd be surprised if this weren't true 
-- in most countries. 
create table city (
    country_code char(2) not null references country (country_code), 
    name varchar(35) not null, 
    population integer not null check (population > 0), 
    primary key (country_code, name) 
); 

insert into city values 
('US', 'Rome, GA', 36303), 
('US', 'Washington, DC', 632323), 
('US', 'Springfield, VA', 30484), 
('IT', 'Rome', 277979), 
('IT', 'Milan', 1324110), 
('IT', 'Bari', 320475), 
('IN', 'Mumbai', 12478447), 
('IN', 'Patna', 1683200), 
('IN', 'Cuttack', 606007); 

一个国家的人口最多。

select country.country_code, max(city.population) as max_population 
from country 
inner join city on country.country_code = city.country_code 
group by country.country_code; 

有几种方法可以用来获得你想要的结果。一种方法是在公用表表达式上使用内部联接。

with max_population as (
    select country.country_code, max(city.population) as max_population 
    from country 
    inner join city on country.country_code = city.country_code 
    group by country.country_code 
) 
select city.country_code, city.name, city.population 
from city 
inner join max_population 
     on max_population.country_code = city.country_code 
     and max_population.max_population = city.population; 

另一种方法是在子查询上使用内部联接。 (公共表表达式的文云“到”主查询。使用别名“max_population”,查询需要没有进一步的变化工作。)

select city.country_code, city.name, city.population 
from city 
inner join (select country.country_code, max(city.population) as max_population 
      from country 
      inner join city on country.country_code = city.country_code 
      group by country.country_code 
      ) max_population 
     on max_population.country_code = city.country_code 
     and max_population.max_population = city.population; 

另一种方法是使用一个窗口功能一个子查询。您需要从子查询中进行选择,因为您不能在WHERE子句中直接使用rank()的结果。也就是说,这是有效的。

select country_code, name, population 
from (select country_code, name, population, 
     rank() over (partition by country_code 
        order by population desc) as city_population_rank 
     from city 
    ) city_population_rankings 
where city_population_rank = 1; 

但是这并不是,即使它乍一看更有意义。

select country_code, name, population, 
     rank() over (partition by country_code 
        order by population desc) as city_population_rank 
from city 
where city_population_rank = 1; 

ERROR: column "city_population_rank" does not exist 
+0

我可以错误地使用GROUP BY吗?如果我按照错误所说的做了GROUP BY c.name,ci.name,ci.population,那么如果我不添加哪个组是错误的,它会给我一个相同的表。 – Paigentry 2013-03-12 01:31:53

+0

这个答案是正确的,但我不能使用它,因为它是为了我所知道的先进的。有没有更简单的方法来做到这一点? – Paigentry 2013-03-12 01:46:06

+0

@Paigentry:更新了答案。我认为你更有可能错误地理解* GROUP BY。 GROUP BY不是一个聚合函数,但MAX()是。 GREATEST()不是一个聚合函数;这是一个条件函数。 GROUP BY需要一个聚合函数。 – 2013-03-12 02:37:44

0

做到这一点,最好的办法是更新的PostgreSQL的版本是窗口。Docs。)在需要做出丑陋的事情之前,当您想要将最后一个特定行的其他列(例如,具有最大人口的行)输入到最终输出中时。

WITH preliminary AS 
    (SELECT country_code, city_name, population, 
     rank() OVER (PARTITION BY country_code ORDER BY population DESC) AS r 
     FROM country 
     NATURAL JOIN city) -- NATURAL JOIN collapses 2 country_code columns into 1 
SELECT * FROM preliminary WHERE r=1; 

这也做了在一个国家的两个或多个大城市有相同的人口固然不太可能的情况下智能。

[编辑回应评论]

窗口之前,我通常的做法是

SELECT country_code, city_name, population 
FROM country co1 NATURAL JOIN city ci1 
WHERE ROW(co1.country_code, ci1.population) = 
    (SELECT co2.country_code, ci2.population 
    FROM country co2 NATURAL JOIN city ci2 
    WHERE co1.country_code = co2.country_code 
    ORDER BY population DESC LIMIT 1) 
    AS subquery; 
-- note for lurkers, some other DBs use TOP 1 instead of LIMIT 

的这个性能是不是太糟糕,因为如果DB被收录智能Postgres的公司优化子查询。将这与Mike Sherrill ’的答案的子查询方法的内部联接进行比较。

青睐我们教练的回答,对不对?使用迄今为止的设备,它可能会效率低下,在关系不完整的情况下,或者两者兼而有之。

+0

再一次,这可能是正确的答案,但它对于我所知道的来说太过先进。我不希望这么做,因为这是我的第一个数据库类,也是我第一次使用聚合函数。是否有类似于我的格式?没有WITH,因为那还没有被引入。 – Paigentry 2013-03-12 01:54:40