Отличается от Count и SQl Server 2005 - PullRequest
0 голосов
/ 10 апреля 2010

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

Упрощенная схема таблицы

Product
  ProductID
  Product Name
  Artist Name

OrderItem
 ProductID
 Qty


So results would look like this...

PID    artist                 qty
34432, 'Jimi Hendrix',        6543
54833, 'stevie ray vaughan'   2344
12344, 'carrie underwood',    1

Ответы [ 6 ]

2 голосов
/ 10 апреля 2010

Используйте это:

with summed_sales_of_each_product as 
(
    select p.artist_name, p.product_id, sum(i.qty) as total
    from product p join order_item i 
    on i.product_id = p.product_id
    group by p.artist_name, p.product_id
),
each_artist_top_selling_product as
(
    select x_in.artist_name, x_in.product_id, x_in.total 
    from summed_sales_of_each_product x_in where total = 
        (select max(x_out.total) 
            from summed_sales_of_each_product x_out 
            where x_out.artist_name = x_in.artist_name)
)
select top 3
artist_name, product_id, total
from each_artist_top_selling_product
order by total desc

Но вы не можете остановиться на этом запросе, как насчет того, если на одном артисте есть два продукта, которые имеют самые высокие продажи? Вот как данные, как это ...

beatles  yesterday       1000
beatles  something       1000
elvis    jailbreak rock  800
nirvana  lithium         600
tomjones sexbomb         400

... приведет к выполнению следующего запроса:

beatles  yesterday       1000
beatles  something       1000
elvis    jailbreak rock  800

Какой выбрать? вчера что ли? Поскольку вы не можете произвольно выбрать одно из другого, вы должны перечислить оба. Кроме того, что, если топ-10 самых продаваемых принадлежат битлз и являются галстуками, каждый из которых имеет количество 1000? Поскольку это самая лучшая вещь, которую вы избегаете (то есть сообщаете об одном и том же исполнителе в топ-3), вам нужно изменить запрос, чтобы отчет из топ-3 выглядел так:

beatles  yesterday       1000
beatles  something       1000
elvis    jailbreak rock  800
nirvana  lithium         600

Изменить:

with summed_sales_of_each_product as 
(
    select p.artist_name, p.product_id, sum(i.qty) as total
    from product p join order_item i 
    on i.product_id = p.product_id
    group by p.artist_name, p.product_id
),
each_artist_top_selling_product as
(
    select x_in.artist_name, x_in.product_id, x_in.total 
    from summed_sales_of_each_product x_in 
    where x_in.total = 
        (select max(x_out.total) 
            from summed_sales_of_each_product x_out 
            where x_out.artist_name = x_in.artist_name)
),
top_3_total as
(    
    select distinct top 3 total 
    from each_artist_top_selling_product
    order by total desc
)
select artist_name, product_id, total 
from each_artist_top_selling_product
where total in (select total from top_3_total)
order by total desc

Как насчет того, чтобы у "Битлз" был другой продукт, имеющий 900 кол-во? Будет ли работать приведенный выше запрос? Да, это все еще будет работать. Поскольку top_3 CTE относится только к уже отфильтрованному верхнему количеству каждого художника. Так что это исходные данные ...

beatles  yesterday       1000
beatles  something       1000
beatles  and i love her  900
elvis    jailbreak rock  800
nirvana  lithium         600
tomjones sexbomb         400

... все равно приведет к следующему:

beatles  yesterday       1000
beatles  something       1000
elvis    jailbreak rock  800
nirvana  lithium         600
1 голос
/ 10 апреля 2010

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

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

select top 3 sales_by_item.ProductID, 
             sales_by_item.Artist, 
             sales_by_item.Qty 
from 
(
    select * from product x
    inner join OrderItem y 
    on x.productid = y.productid
    group by productid, Artist
) sales_by_item
inner join
(
    select artist, max(qty) as maxqty
    from product x
    inner join OrderItem y 
    on x.productid = y.productid
    group by artist
) max_by_artist
on sales_by_item.artist = max_by_artist.artist
    and sales_by_item.qty = max_by_artist.maxqty
order by sales_by_item.qty

Отредактировано, чтобы сделать имена подзапросов более информативными

1 голос
/ 10 апреля 2010

Если я правильно понял вашу схему, вы сможете сделать это следующим образом:

select top 3 * from(
   select p.ProductId, p.ArtistName, sum(o.qty) as qty from Product p, OrderItem o
   where p.ProductId = o.ProductId
   group by p.productId, p.ArtistName
   order by sum(o.qty)
)
0 голосов
/ 10 апреля 2010

Вторая попытка. Я не в состоянии протестировать этот код, и я не уверен, правильно ли настроен этот раздел «раздел по». Идея такова:

  • Внутренний запрос получает сумму Qty для всех товаров / исполнителей и использует функцию row_number () для нумерации их, начиная с самого большого, и сбрасывает порядок для каждого исполнителя. (Это можно сделать, но мой синтаксис может быть отключен.)
  • Внешний запрос выбирает первый (наибольший) элемент для каждого исполнителя и возвращает только первые три (ordere by Qty)
  • Если два лучших артиста связывают общее количество, я произвольно разрываю связь в пользу «самого раннего» альбома.

(Я стараюсь избегать использования «Top n», но уже поздно и я не хочу заниматься другой функцией row_number ().)

SELECT top 3 
  ProductId
  ,ArtistName
  ,Qty
 from (--  Products + Artists by total qty
       select
         pr.ProductId
        ,pr.ArtistName
        ,sum(oi.Qty) Qty
        ,row_number() over (partition by pr.ArtistName order by pr.ArtistName, sum(oi.Qty) desc, pr.ProductId) Ranking
       from Product pr
        inner join OrderItem oi
         on oi.ProductID = pr.ProductID
       group by pr.ProductId, pr.ArtistName) BestSellers
 where Ranking = 1
 group by ProductId, ArtistName) BestArtists
 order by Qty desc
0 голосов
/ 10 апреля 2010

Анализируя ваш запрос, кажется, что результаты должны быть наивысшим количеством продукта для трех лучших артистов. Итак, если у Джими Хендрикса 10 лучших продуктов, а у Стиви Рэя Вогана 11-е, вы хотите, чтобы у Джими был самый высокий продукт, а у Стиви - самый высокий.

With ProductRanksForArtists As
    (
    Select P.ProductId, P.ArtistName, Sum(O.Qty) As Total
        , ROW_NUMBER OVER( PARTITION BY P.ArtistName ORDER BY Sum(O.Qty) DESC ) As ProductRank
    From Product As P
        Join OrderItem As O
            On O.ProductId = P.ProductId
    Group By P.ProductId, P.ArtistName
    )
    , HighestProductForArtists As 
    (
    Select ProductId, ArtistName, Total
        , ROW_NUMBER OVER( ORDER BY Total DESC ) As TotalRank
    From ProductRanksForArtists
    Where ProductRank = 1
    )
Select ProductId, ArtistName, Total
From HighestProductForArtists
Where TotalRank <= 3
0 голосов
/ 10 апреля 2010

Попробуйте это

Выберите лучших 3 исполнителей, количество (исполнитель) из таблицы имен группы по исполнителю по количеству исполнителей (исполнитель) desc

...