【问题标题】:Get primary key of aggregated, group by SQL query using PostgreSQL使用 PostgreSQL 获取聚合的主键,按 SQL 查询分组
【发布时间】:2009-07-28 14:33:35
【问题描述】:

我正在努力使用 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
)

现在,我想使用 location.type = xxx 获取每个位置的所有价格最低的事物记录。

类似:

SELECT min(price) FROM thing
INNER JOIN location ON (thing.location_id = location.id)
WHERE type = xxx
GROUP BY location_id

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

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    使用这个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
    

    【讨论】:

    • 完美,这正是我想要的。
    【解决方案2】:

    也许使用子查询

    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;
    

    【讨论】:

      【解决方案3】:

      我是一名 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 的排名函数,它们会让它变得更简单一些。

      【讨论】:

      • 这也是我最初想出的。这个查询的问题是,如果最低价格不是唯一的,它将返回一个位置的多个事物列。
      • 根据描述,我认为这就是您要查找的内容。如果根据最低价格有重复的东西,你会选择哪个? (反问,因为你已经有了答案——row_number() 是一个非常有用的扩展。)
      【解决方案4】:

      试试这个查询

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-20
        • 2021-05-19
        • 1970-01-01
        相关资源
        最近更新 更多