使用PostgreSQL获取聚合分组的主键

3
我正在努力使用PostgreSQL创建一个涉及聚合的SQL查询。考虑以下表:
CREATE TABLE thing (
  id INT NOT NULL PRIMARY KEY,
  price NUMERIC(10,2) NOT NULL,
  description VARCHAR(255) NOT NULL,
  url VARCHAR(255) NOT NULL,
  location_id INT NOT NULL REFERENCES location(id)
)

CREATE TABLE location (
  id INT NOT NULL PRIMARY KEY,
  type INT NOT NULL,
  name VARCHAR(255) NOT NULL
)

现在,我想获取每个位置的所有物品记录,其中位置类型为xxx且价格最低。
类似于:
SELECT min(price) FROM thing
INNER JOIN location ON (thing.location_id = location.id)
WHERE type = xxx
GROUP BY location_id

这将列出每个类型为xxx的位置的最低价格,但我如何从thing表中获取这些列的行(或它们的主键)?
4个回答

5
使用这个 PostgreSQL 扩展程序:
SELECT  DISTINCT ON (location.id) thing.*
FROM    location
JOIN    thing
ON      thing.location_id = location_id
WHERE   type = 1
ORDER BY
        location.id ASC, price ASC

这将只选择每个location.id的第一行。

由于你的行是按location.id,然后按price排序的,因此这将是价格最低的行。

在新的PostgreSQL 8.4中,您还可以使用窗口函数:

SELECT  *
FROM    (
        SELECT  thing.*, ROW_NUMBER() OVER (PARTITION BY location_id ORDER BY price) AS rn
        FROM    location
        JOIN    thing
        ON      thing.location_id = location_id
        WHERE   type = 1
        ) q
WHERE   rn = 1

完美,那正是我在寻找的。 - Haes

0

尝试这个查询

select thing.id,thing.description,thing.url,low.location_id,low.minimum from
(select thing.location_id,min(price) as minimum from thing
 join location on thing.location_id=location.id
  where location.type = 13 group by location_id) as low
   inner join thing on thing.location_id = low.location_id

0

或许可以使用子查询

SELECT t.id,t.description,t.price FROM 
  ( SELECT location_id, min(price) FROM thing
      INNER JOIN location ON (thing.location_id = location.id)
      WHERE type = xxx
      GROUP BY location_id
   ) AS lowest
   INNER JOIN thing AS t
     ON t. location_id  = lowest.location_id;

0

我是一个SQL Server专家,但是以下内容应该符合SQL-92标准并且应该能够正常工作:

select th.*
 from thing th
  inner join (select lo.id, min(th.price) minPrice
               from location lo
                inner join thing th
                 on th.location_id = lo.id
               where lo.type = xxx
               group by lo.id) minSet
   on minSet.id = th.location_id
    and th.price = minSet.minPrice

请注意,我没有设置表进行测试,因此可能会有一两个错别字。
虽然它确实可以工作,但看起来很笨拙。如果Postgres有类似SQL排名函数的东西,那么它们会使它变得更简单。

这也是我最初想到的。这个查询的问题在于,如果最低价格不唯一,它将为一个位置返回多个列。 - Haes
根据描述,我认为那就是你要找的。如果有基于最低价格的重复内容,你想选择哪一个?(这是一个反问,因为你已经有了答案——row_number()是一个非常有用的扩展。) - Philip Kelley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接