Не могу собрать запрос MSSQL

Есть 3 таблицы: Countries, Brands, Cars. Вот фиддл, с готовыми таблицами: http://sqlfiddle.com/#!18/34629/63

Задача: Вывести список самых дешевых автомобилей каждой марки (название авто + название марки)

Попытка решения:

select top 1 Cars.Name, Brands.Name, min(Price) from Cars
join Brands on Cars.BrandID = Brands.ID
group by Cars.Name
ORDER BY min(Price)

Подскажите, в каком направлении копать?


Ответы (2 шт):

Автор решения: Сергей
  1. top 1 выглядит излишним. Вы уже группируете по марке.
  2. В задании выше у вас не написано про порядок вывода. ORDER BY min(Price) тогда излишен, при автоматической проверке может вызывать отказ.
    Да и избыточность кода это повышает, если нет условия обязательного.

Предлагаемый код (убрал прежний нерабочий код, дописал новый):

select Cars.Name, Brands.Name, Price 
from Cars 
join Brands on Cars.BrandID = Brands.ID
WHERE (BrandID, Price) IN
(SELECT BrandID, min(Price) 
FROM Cars
GROUP BY BrandID);

Я знаю mySQL, а не sql-server, не получилось запустить в фиддле, выдает ошибку (указал ниже). Но в mySQL я получил результат:

Query result:
+-----------+------------+-------+
| Name      | Name       | Price |
+-----------+------------+-------+
| Rio       | KIA        | 734   |
| Solaris   | Hyundai    | 746   |
| Granta    | LADA       | 404   |
| Corolla   | Toyota     | 1173  |
| Outlander | Mitsubishi | 1449  |
| Qashqai   | Nissan     | 1120  |
+-----------+------------+-------+
Affected rows: 6

Ошибка в фиддле: "An expression of non-boolean type specified in a context where a condition is expected, near ','."

→ Ссылка
Автор решения: Andrew Nikolaev

В MS SQL есть такая штука TOP 1 WITH TIES. Вот как это будет выглядеть:

SELECT TOP 1 WITH TIES
  Cars.Name, Brands.Name, Cars.Price
FROM Cars
  INNER JOIN Brands ON Cars.BrandID = Brands.ID
ORDER BY ROW_NUMBER() OVER ( PARTITION BY Cars.BrandID ORDER BY Cars.Price )

Второй способ, дающий аналогичный результат:

SELECT 
  SQ.CarsName, SQ.BrandsName, SQ.Price 
FROM
(
  SELECT RANK() OVER ( PARTITION BY Cars.BrandID ORDER BY Cars.Price ) 
AS RankRow,
    Cars.Name AS CarsName, Brands.Name AS BrandsName, Cars.Price AS 
Price
  FROM Cars
    INNER JOIN Brands ON Cars.BrandID = Brands.ID
) SQ
WHERE SQ.RankRow = 1

Рабочий вариант, предложенный Сергеем будет выглядеть так:

SELECT 
  c.Name AS CarsName, 
  SQ.BrandName AS BrandName, 
  c.Price AS Price 
FROM Cars c
INNER JOIN 
(
  SELECT 
    b.ID AS BrandID, b.Name AS BrandName, MIN(c.Price) AS Price
  FROM Cars c
    INNER JOIN Brands b ON c.BrandID = b.ID
  GROUP BY b.ID, b.Name
) SQ ON c.Price = SQ.Price AND c.BrandID = c.BrandID

В этом случае результат скорее подогнанный, потому что делать JOIN по цене как то плохо выглядит, а включить Cars.Name в GROUP BY мы не можем, получим не правильный результат.

→ Ссылка