如何在关系字段的最大值上加入多对多的关系

时间:2013-09-28 10:47:04

标签: sql postgresql

我有三张桌子:

Shop_Table
   shop_id
   shop_name

Sells_Table
   shop_id
   item_id
   price

Item_Table
   item_id
   item_name

Sells_Table通过FK将商品和商店表链接到他们的ID。我试图从每个商店获得最昂贵的商品,即表格的输出:

(shop_name, item_name, price)
(shop_name, item_name, price)
(shop_name, item_name, price)
(shop_name, item_name, price)
...

其中price是每个商店的最高价格项目。我似乎可以实现(shop_name,max(price))但是当我尝试包含item_name时,我获得了shop_name的多个条目。我目前的方法是

create view shop_sells_item as
select s.shop_name as shop, i.item_name as item, price
from Shop_Table s
join Sells_Table on (s.shop_id = Sells_Table.shop_id)
join Item_Table i on (i.item_id = Sells_Table.item_id);

select shop, item, max(price)
from shop_sells_item
group by shop;

然而,我收到错误说item must appear in the GROUP BY clause or be used in an aggregate function,但如果我包含它,那么我没有得到每个商店的最高价格,而是我得到每个商店的最高价格,项目对是没用。

另外,使用视图的最佳方式是什么?可以通过一个查询来完成吗?

5 个答案:

答案 0 :(得分:2)

你可以用Postgresql方式做到:

select distinct on (shop_name) shop_name, item_name, price 
from shop_table
join sells_table using (shop_id) 
join item_table using (item_id)
order by shop_name, price;

答案 1 :(得分:1)

  

我想从每家商店买到最贵的商品,

一个商店最贵的商品的定义:=此商店没有更贵的商品

SELECT *
FROM Sells_Table st
WHERE NOT EXISTS (
    SELECT * FROM Sells_Table nx
    WHERE nx.shop_id = st.shop_id
    AND nx.price > st.price
);

现在我们有与所需项目对应的sells_table条目:结果集的骨架。只需添加

SELECT sh.shop_name -- <<-- Meat
    , it.item_name  -- <<-- Meat
    , st.price
FROM Sells_Table st
JOIN shop_table sh ON sh.shop_id = st.shop_id  -- <<-- Meat
JOIN items_table it ON it.item_id = st.item_id -- <<-- Meat
WHERE NOT EXISTS (
    SELECT * FROM Sells_Table nx
    WHERE nx.shop_id = st.shop_id
    AND nx.price > st.price
);

答案 2 :(得分:1)

请注意,下面的查询并不涉及一个商店中的多个商品具有相同的最高价格(它们都是最贵的商品)的情况:

SELECT
    s.shop_name,
    i.item_name,
    si.price
FROM
    Sells_Table si
JOIN
    Shop_Table s
ON
    si.shop_id = s.shop_id
JOIN
    Item_Table i
ON
    si.item_id = i.item_id
WHERE
    (shop_id, price) IN (
        SELECT
            shop_id,
            MAX(price) AS price_max
        FROM
            Sells_Table
        GROUP BY
            shop_id
    );

答案 3 :(得分:1)

可能最快:

SELECT s.shop_name, i.item_name, sub.price
FROM  (
   SELECT DISTINCT ON (shop_id) shop_id, item_id, price 
   FROM   sells_table
   ORDER  BY shop_id, price DESC -- , item_id -- for 1 item only
   ) sub
JOIN   item_table i USING (item_id)
JOIN   shop_table s USING (shop_id);
  • 要获得the most expensive item from each store,您必须ORDER BY .. price DESC

  • 上述查询为您提供了共享最高价格的商店的所有商品。可以不止一个。如果您总是需要单个项,则必须定义如何断开关系。例如,取消注释上方的其他ORDER BY项,以选择最小item_id项。

  • 首先聚合(或选择)和然后加入到与聚合或选择本身无关的其他表格通常会更快。

此相关答案中DISTINCT ON的详细信息:
Select first row in each GROUP BY group?

您可以从上面的查询轻松创建VIEW,性能与原始SQL大致相同。

最佳表现指数

如果您想要 快速 ,请尝试使用以下多列索引:

CREATE INDEX sells_table_special_idx
ON sells_table (shop_id, price DESC, item_id)

请注意 second 列上的降序 第三个​​列仅用于使其成为covering index,仅适用于PostgreSQL 9.2或更高版本。

答案 4 :(得分:0)

你的问题听起来有点奇怪,但让我看看我是否可以改写它。

对于每家商店,我想找到他们卖的最贵的东西。从那个项目你想要它的名称,它的价格和销售它的商店。但是,您还声明您使用MIN()获得最低价格......这是最高价还是最低价。无论哪种方式,只需更改min()vs max()

首先只展示商店及其销售的最高价格(或最低价)商品 - 无论它是什么

选择shop_id,max(价格)仅按shop_id分组...以此为基础,然后获得与此最高价格相匹配的商品...商店可以有10件物品,价格为199美元,你有没有任何标识你只想要1和处理它的标准。我正在接受

select
      FindingMax.Shop_id,
      shop.shop_name,
      FindingMax.HighestPrice,
      Item_Table.item_name
   from
      ( select st.shop_id,
               max( st.price ) as HighestPrice
           from
               sells_table st
           group by
               st.shop_id ) as FindingMax
      JOIN Shop_Table shop
         on FindingMax.shop_id = shop.shop_id
      JOIN sells_table st2
         on FindingMax.shop_id = st2.shop_id
         AND FindingMax.HighestPrice = st2.price
         JOIN Item_Table
            on st2.item_id = Item_Table.item_id