группировать по проблемам

Группа SQL по проблеме

У меня есть группа SQL по проблеме. Моя таблица имеет следующий вид.

Cust_id.  Price_id     Price. 
----------------------------  
1.          556.        5000. 
-----------------------------  
2.          654.         600. 
2.          432.         487. 
2.          546.         500. 
---------------------------  
3.          455.         200. 
3.          877.         143. 
3.          123.         879. 

Теперь, когда я запускаю этот запрос:

Select  cust_id,  max(price) as max, min(price) as min. 
From table. 
Group by cust_id. 

Я получил.

Cust_id.      Max.        Min. 
1.           5000.       5000. 
2.            600.        487. 
3.            879.        143. 

Но то, что я действительно хочу, это не максимальная и минимальная цена, а price_id, связанный с ценой.
Такими будут результаты.

Cust_id.       Max.        Min.   
1.             556.        556.   
2.             654.        432.   
3.             123.        877.    

Я в недоумении, как это сделать. Я думаю, что приведенный выше запрос будет своего рода подзапросом, но это все, что я понял.


person dlb    schedule 26.09.2010    source источник
comment
Какой движок БД вы используете?   -  person Lucero    schedule 27.09.2010
comment
Какую базу данных вы используете? (SQL Server, MySQL, PostGRES, ...)   -  person Andomar    schedule 27.09.2010
comment
@dlb - Не знаю, почему вы отменили мои изменения ... но некрасивый вопрос не поможет получить ответы ...   -  person Mitch Dempsey    schedule 27.09.2010
comment
У вас есть cuts_id и cust_id в вопросе — выберите один!   -  person Jonathan Leffler    schedule 27.09.2010
comment
возможный дубликат T-SQL: выбор столбца на основе MAX (другой столбец)   -  person Lucero    schedule 27.09.2010
comment
@webdestroya Я не хотел наступать на твои правки. Я тоже пытался отредактировать пост. Использование моего iPad не было хорошей идеей, чтобы попытаться исправить формат. Cuts_id был опечаткой, которую я исправил. Я использую базу данных Oracle 10g. Я не включил эту информацию, потому что в какой-то момент запрос нужно будет перенести на MS SQL Server.   -  person dlb    schedule 27.09.2010


Ответы (4)


Использовать:

   SELECT x.cust_id,
          y.price_id AS max,
          z.price_id AS min
     FROM (SELECT t.cust_id,  
                  MAX(t.price) as max, 
                  MIN(t.price) as min
             FROM TABLE t
         GROUP BY t.cust_id) x
LEFT JOIN TABLE y ON y.cust_id = x.cust_id
                 AND y.price = x.max
LEFT JOIN TABLE z ON z.cust_id = x.cust_id
                 AND z.price = x.min

Проблема в том, что если у cust_id есть две записи с одинаковой высокой (или низкой) ценой, вы увидите дубликаты и вам нужно будет предоставить логику для обработки связей.

person OMG Ponies    schedule 26.09.2010
comment
@Jonathan Leffler: я использовал запрос, предоставленный OP, на его основе. - person OMG Ponies; 27.09.2010
comment
нуждается в настройке - OP хочет получить максимальную / минимальную цену price_ids, а не цены. - person martin clayton; 27.09.2010

Это должно сработать для движков с функциями ранжирования/аналитики:

SELECT Pmin.Cust_id, Pmax.Price_id Price_max_id, Pmin.Price_id Price_min_id FROM
(SELECT t.*, ROW_NUMBER() OVER (PARTITION BY t.Cust_id ORDER BY t.Price DESC) ix FROM @table t) Pmin
JOIN (SELECT t.*, ROW_NUMBER() OVER (PARTITION BY t.Cust_id ORDER BY t.Price ASC) ix FROM @table t) Pmax
    ON Pmin.Cust_id = Pmax.Cust_id
WHERE (Pmin.ix = 1) AND (Pmax.ix = 1)
person Lucero    schedule 26.09.2010
comment
Использование RANK может возвращать дубликаты; ROW_NUMBER гарантирует, что дубликаты не будут возвращены. - person OMG Ponies; 27.09.2010
comment
Да, исправил это еще до того, как увидел ваш комментарий. Спасибо хоть. - person Lucero; 27.09.2010

Это классическая проблема, с которой сталкивается большинство людей, использующих MySQL, с GROUP BY. MySQL разрешает запросы, которые не разрешены в стандартном SQL и в большинстве других типов баз данных.

Вам нужна полная строка, включая столбцы, отличные от cust_id, по которым вы группируете, чтобы строка имела самую высокую (или самую низкую) цену в этой группе. Вы не можете получить это от GROUP BY.

Чего я действительно хочу, так это... связать price_id с ценой.

Но какой price_id вам нужен, из строки с максимальной ценой или из строки с минимальной ценой? Это могут быть разные строки.

Cust_id.  Price_id     Price
----------------------------
2.          654          600  <-- max price, price_id 654
2.          432          487  <-- min price, price_id 432
2.          546          500

Что, если несколько строк имеют одинаковую цену, но разные значения price_id? Должен ли он возвращать 654 или 546?

Cust_id.  Price_id     Price
----------------------------
2.          654          600  <-- max price, price_id 654
2.          432          487
2.          546          600  <-- max price, price_id 546

Вместо этого, если вам нужен price_id максимальной и минимальной цен, вам нужны две строки: строка, в которой не существует другой строки с тем же cust_id и более высокой ценой, и строка, в которой не существует другой строки с тем же самым значением. cust_id и более низкая цена.

SELECT tmax.cust_id, tmax.price_id, tmax.price, tmin.price_id, tmin.price
FROM table tmax
JOIN table tmin ON tmax.cust_id = tmin.cust_id
WHERE NOT EXISTS (SELECT * FROM table t1 WHERE t1.cust_id = tmax.cust_id AND t1.price > tmax.price) 
  AND NOT EXISTS (SELECT * FROM table t2 WHERE t2.cust_id = tmin.cust_id AND t2.price > tmin.price) 
person Bill Karwin    schedule 26.09.2010

Вот подход SQL Server

with Data as 
(
    select 1 Cust_id, 556 Price_id,  5000  Price union ALL
    select 2,          654,          600 union ALL
    select 2,          432,          487 union ALL
    select 2,          546,          500 union ALL
    select 3,          455,           200 union ALL
    select 3,          877,           143 union ALL
    select 3,          123,           879
),
Prices as
(
    select Cust_id, MAX(Price) MaxP, MIN(Price) MinP
    from Data
    group by Cust_id
)
select Prices.Cust_id
        ,Data.Price MaxPrice
        , d2.Price MinPrice
from Prices
inner join Data  on Data.Cust_id = Prices.Cust_id and Data.Price = Prices.MaxP
inner join Data d2 on d2.Cust_id = d2.Cust_id and d2.Price = Prices.MinP
person Scott Weinstein    schedule 26.09.2010
comment
Это также имеет проблему дубликатов. - person Lucero; 27.09.2010