【问题标题】:Distinct with Count and SQl Server 2005与 Count 和 SQl Server 2005 不同
【发布时间】:2010-04-10 00:56:40
【问题描述】:

尝试处理一个查询,该查询将返回前 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

【问题讨论】:

  • 一个艺术家可以有多个产品,因此查询不需要在结果中拉 Jimi Hendrix 2x。
  • 但是数量值是艺术家最高的单个值,还是所有数量之和?
  • 他希望三位艺术家在制作个人专辑方面最成功。
  • 如果您只需要每行一位艺术家,为什么结果中会返回 productId?如果同一位艺术家的两种不同产品的销售额最高会怎样?
  • 顺便说一句,您使用的是 SQL Server 2005 还是 SQL Server 2008?如果是这样,您能否更新问题上的标签以反映这一点?

标签: sql-server count distinct


【解决方案1】:

使用这个:

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

【讨论】:

  • 非常好的迈克尔!感谢大家对此的帮助。
【解决方案2】:

如果我正确理解了您的架构,您应该可以这样做:

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)
)

【讨论】:

  • 尝试运行它但收到此错误。消息 1033,级别 15,状态 1,第 7 行 ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效,除非还指定了 TOP 或 FOR XML。
【解决方案3】:

如果艺术家有两个销量相同的顶级产品,我不知道你想做什么——如果出现平局,这将返回两个。

如果您想添加其他条件,例如“最近的”,您必须将其添加到两个子查询中。

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

已编辑以使子查询名称更具描述性

【讨论】:

    【解决方案4】:

    第二次尝试。我无法测试这段代码,我不确定我是否正确配置了“partition by”子句。这个想法是:

    • 内部查询获取所有产品/艺术家的数量总和,并使用 row_number() 函数从最大的开始对其进行编号,并重置每个艺术家的排序。 (可以这样做,但我的语法可能不正确。)
    • 外部查询为每个艺术家挑选出第一个(最大的)项目,并且只返回前三个(按数量排序)
    • 如果某位艺术家的前两个产品的总数量并列,我会随意打破平局,支持“最早”的专辑。

    (我尽量避免使用“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
    

    【讨论】:

      【解决方案5】:

      分析您的请求,听起来结果应该是前三名艺术家的最高产品数量。因此,如果 Jimi Hendrix 的产品数量排在前 10 位,而 Stevie Ray Vaughan 排在第 11 位,那么您希望 Jimi 的产品数量最高,然后 Stevie 的产品数量最高。

      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
      

      【讨论】:

      • 仍然找回了三张唱片中的两位相同的艺术家。
      【解决方案6】:

      试试这个

      从表名组中选择前 3 名艺术家,count(artist) 按艺术家排序按艺术家计数(artist) desc

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-06
        • 2015-01-22
        • 2010-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多