Проблема с уникальным SQL-запросом

#sql-server #sql-server-2005

#sql-сервер #sql-server-2005

Вопрос:

Я хочу выбрать все записи, но запрос возвращает только одну запись для каждого названия продукта. Моя таблица выглядит похоже на:

 SellId   ProductName Comment
1          Cake        dasd 
2          Cake        dasdasd
3          Bread       dasdasdd  
  

где название продукта не уникально. Я хочу, чтобы запрос возвращал одну запись для каждого ProductName с результатами типа:

 SellId   ProductName Comment
1          Cake        dasd 
3          Bread       dasdasdd 
  

Я попробовал этот запрос,

 Select distict ProductName,Comment ,SellId from TBL#Sells
  

но он возвращает несколько записей с одним и тем же именем продукта. Моя таблица на самом деле не так проста, как эта, это всего лишь образец. Каково решение? Это понятно?

Комментарии:

1. Какова цель вашего кода? Что вы пытаетесь сделать?

2. Учитывая более одного комментария для cake, что вы хотите видеть в столбце комментариев для единственной строки, возвращаемой для cake?

3. Я хочу выбрать все записи, но ни одно название продукта не должно повторяться в запросе

Ответ №1:

 Select  ProductName, 
min(Comment) , min(SellId) from TBL#Sells
group by ProductName
  

Если вам нужна только одна запись для имени продукта, вам, конечно, придется выбрать, какое значение вы хотите для других полей.

Если вы агрегируете (используя group by), вы можете выбрать aggregate function , htэто функция, которая принимает список значений и возвращает только одно: здесь я выбрал MIN : это наименьшее значение для каждого поля.

ПРИМЕЧАНИЕ: комментарий и идентификатор продажи могут поступать из разных записей, поскольку используется значение MIN…

Другие агрегаты, которые могут оказаться полезными :

 FIRST : first record encountered
LAST : last record encoutered
AVG : average 
COUNT : number of records
  

преимущество first / last в том, что все поля взяты из одной записи.

Комментарии:

1. Я думаю, он скорее хочет ‘min’.

2. @leppie, действительно, изменил его соответствующим образом, tx

3. Спасибо, я получил свой ответ. «Большое спасибо»

4. Единственное, с чем я был бы осторожен в этом ответе, это то, что комментарий не обязательно будет соответствовать идентификатору SELLID. Поскольку вы сказали, что ваша таблица более сложная, я бы просто посмотрел, если вы ожидаете, что значения будут из совпадающих строк. Комментарий MIN на самом деле может исходить из строки, отличной от SellId.

5. Я думаю об этом, что с запросом, который написал Питер , productname будет уникальным и не повторится в выходном результате?

Ответ №2:

 SELECT S.ProductName, S.Comment, S.SellId
FROM
   Sells S
   JOIN (SELECT MAX(SellId)
        FROM Sells
        GROUP BY ProductName) AS TopSell ON TopSell.SellId = S.SellId
  

В качестве выбранного вами комментария будет получен последний комментарий, предполагающий, что SellId является автоматически увеличиваемым идентификатором, который повышается.

Комментарии:

1. Спасибо, я получил свой ответ. «Большое спасибо»

2. не следует ли нам включить название продукта в join?

3. Нет, потому что у меня уже есть 1 идентификатор на имя в подзапросе. Вложенный запрос получает последнюю запись по названию продукта, а 1-я часть получает остальные сведения.

Ответ №3:

Я знаю, у вас уже есть ответ, я хотел бы предложить способ, который был бы самым быстрым с точки зрения производительности для меня в аналогичной ситуации. Я предполагаю, что SellId является первичным ключом и идентификатором. Для лучшей производительности вам нужен индекс для ProductName.

 select 
    Sells.* 
from 
(
    select 
        distinct ProductName 
    from 
        Sells
) x
join 
    Sells 
on 
    Sells.ProductName = x.ProductName
    and Sells.SellId =
    (
        select 
            top 1 s2.SellId 
        from 
            Sells s2 
        where 
            x.ProductName = s2.ProductName 
        Order By SellId
    )
  

Более медленный метод (но все же лучше, чем группировать по и MIN в длинном столбце char) заключается в следующем:

 select 
    * 
from
(
    select 
        *,ROW_NUMBER() over (PARTITION BY ProductName order by SellId) OccurenceId 
    from sells
) x
where 
    OccurenceId = 1
  

Преимущество этого в том, что его намного легче читать.

Ответ №4:

 create table Sale
(
    SaleId int not null
        constraint PK_Sale primary key,
    ProductName varchar(100) not null,
    Comment varchar(100) not null
)

insert Sale
values
    (1, 'Cake', 'dasd'),
    (2, 'Cake', 'dasdasd'),
    (3, 'Bread', 'dasdasdd')

-- Option #1 with over()
select *
from Sale
where SaleId in
(
    select SaleId
    from
    (
        select SaleId, row_number() over(partition by ProductName order by SaleId) RowNumber
        from Sale
    ) tt
    where RowNumber = 1
)
order by SaleId

-- Option #2
select *
from Sale
where SaleId in
(
    select min(SaleId)
    from Sale
    group by ProductName
)       
order by SaleId

drop table Sale