#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