2015-06-30 3 views
1

У меня есть таблица, расходные материалы, в котором перечислены цены на элементы из разных поставщиков:Исключить столбец из группы К

| ID | Item | Price | Supplier | 

ID является первичным ключом (только автоматически сгенерированным целого). Продукт - название продукта. Цена - это цена продукта. Поставщик - это внешний ключ (целочисленный).

Я хочу перечислить самую дешевую цену и поставщика по каждому товару.

Я относительно новым для баз данных и до сих пор я получил это:

SELECT Name, MIN(Price), Supplier FROM Supplies GROUP BY Name 

Это, конечно, дает мне ошибку, что

Поставщик не является в агрегатной функции или group by.

Я сделал несколько поисковых запросов Google и прочитал немало статей и ответов на эту тему, но все они кажутся для гораздо более сложных ситуаций, чем у меня, и смущают меня (как сказано, у меня нет большого опыта с базами данных и SQL), или они просто говорят об ошибке, а не о том, как обойти ее.

Любая помощь будет оценена по достоинству. Заранее спасибо.

+4

Какие СУБД вы используете? –

+0

Если две или более цены одинаковы, вы хотите использовать логику тай-брейка? –

+0

Использование HSQLDB. Если две или более цены одинаковы, я бы предпочел, чтобы они отображали оба. –

ответ

1

В зависимости от РСУБД, вы можете быть в состоянии использовать ROW_NUMBER() чтобы присвоить рейтинг для каждой записи и выбрать тот, о том, что первое место , Это быстрее, чем использование дополнительных объединений или коррелированных подзапросов, но в настоящее время, например, не поддерживается в MySQL.

WITH 
    sorted_supplies AS 
(

    SELECT 
     supplies.*, 
     ROW_NUMBER() OVER (PARTITION BY name ORDER BY price) AS price_ordinal 
    FROM 
     supplies 

) 
SELECT 
    * 
FROM 
    sorted_supplies 
WHERE 
    price_ordinal = 1 
; 

Без поддержки ROW_NUMBER() то вы в значительной степени управляется по дороге дополнительных агрегатах и ​​присоединяется к ...

SELECT 
    supplies.* 
FROM 
    supplies 
INNER JOIN 
(
    SELECT 
     name, 
     MIN(price) AS min_price 
    FROM 
     supplies 
    GROUP BY 
     name 
) 
    AS min_prices 
     ON min_prices.name  = supplies.name 
     AND min_prices.min_price = supplies.price 

Обратите внимание, что этот запрос будет возвращать все поставщики с той же цене если они все связаны по самой низкой цене.

Первый запрос может быть принужден делать это с помощью RANK() вместо ROW_NUMBER()

+0

Второй метод работает по желанию. Большое вам спасибо и за быстрый ответ. –

1

В большинстве баз данных, вы можете использовать стандартные оконные функции ANSI:

select s.* 
from (select s.*, min(price) over (partition by item) as minprice 
     from supplies 
    ) s 
where price = minprice; 
+0

@MatBailie. , , Было бы более разумным, чтобы цель заключалась в том, чтобы получить наименьшую цену за товар, а не за поставщика. –

0

Вы можете ранжировать результаты, а затем выбрать самый низкий/высокий рейтинг пункта (на основе порядка сортировки). Если предположить, что Вы используете SQL Server 2008 или выше:

SELECT 
    Item, Price, Supplier 
FROM (
    SELECT 
     ROW_NUMBER() OVER (PARTITION BY Item ORDER BY Price ASC) PriceRank 
     , Item 
     , Price 
     , Supplier 
    FROM 
     Supplies 
    ) supplies_ranked 
WHERE 
    PriceRank = 1 
0

Суть вопроса заключается в следующем - что, если у вас есть более одного поставщика, который предлагает снаряжение для той же самой (низкой) цены? Какой поставщик должен быть возвращен в результирующем наборе?

Способ достижения того, что вам нужно, это получить минимальную цену, а затем внешнюю привязку к той же таблице по продукту = продукт и цена = цена и т. Д.Поймите, что если у вас есть сценарий выше, вы вернете два ряда - по одному с каждым поставщиком, который предложит эту минимальную цену.

3 или 4 новых ответа появилось здесь, так как я начал сочинять это, так что я готов догадаться, что фактический код уже существует. Я оставлю этот текст здесь, как это объясняет «простой английский», почему запрос не может работать так, как вы ожидаете.

0

Если у вас нет partition by (некоторые SQL-иш среды, как Access), то вы можете также сделать это:

select s.name, s.supplier, s.price from 
(select name, min(price) as min_price from supplies group by name) mp 
join supplies s on mp.name=s.name and mp.min_price = s.price 

Это не так эффективно, как partition by, поскольку он имеет подзапрос по самой низкой цене за каждое имя. Обратите внимание, что он вернет несколько поставщиков в случае равенства; вы можете или не захотите этого.