SQL子查询/连接

时间:2010-08-11 20:05:51

标签: sql sql-server

好吧,我是SQL的初学者,所以如果这个问题对你来说太新手了,请原谅。 在Northwind(我确定每个人都知道Northwind) - 我每个月都试图获得最多销售的产品(按数量计算)和1997年销售最少的产品 (使用订单,订单详情,产品表)

由于

更新: 这就是我到目前为止所拥有的

Select p.productname, 
       Datepart(MM,o.OrderDate), 
       od.Quantity 
from orders o 
inner join [Order Details] od 
  on o.OrderID = od.OrderID 
inner join Products p 
  on p.ProductID=od.ProductID 
Where YEAR(o.OrderDate)=1997 
Group by Datepart(MM,o.OrderDate), od.Quantity,p.productname

3 个答案:

答案 0 :(得分:2)

这不是新手问题。这是一个常见的,但也有一个人很难做到正确。他们经常使用多个SQL语句。

但是你,我的朋友,很幸运!您即将与我一起进入分析功能的世界。但请放心 - 如果不符合您的口味,还有其他方法可以解决这个问题。

我假设你只是在修补SQL,只是想要了解更多。如果您实际上是在尝试解决某个特定问题,那么如果您可以更加具体地解决这两点问题,那将会有所帮助:

  1. 您希望结果集看起来像什么?你期待12行,“月”,“最畅销”,“底层卖家”列?一个结果集中有24行可以吗?两个结果集可以吗?
  2. “卖得最少”实际上是否包括没有出售任何东西的产品? (即,他们根本没有出现在本月的订单明细表中。)
  3. SQL:

    WITH
        ProductSalesPerMonth AS
        (
            SELECT
                DATEPART(MM, O.OrderDate) AS MonthNum,
                OD.ProductID,
                SUM(OD.Quantity) AS Quantity
            FROM
                Orders O
                JOIN [Order Details] OD
                ON O.OrderID = OD.OrderID
            WHERE
                O.OrderDate BETWEEN '19970101' AND '19971231'
            GROUP BY
                DATEPART(MM, O.OrderDate),
                OD.ProductID
        ),
        RankedProductSalesPerMonth AS
        (
            SELECT
                PSPM.*,
                ROW_NUMBER() OVER (PARTITION BY PSPM.MonthNum ORDER BY PSPM.Quantity ASC) AS Rank_SoldLeast,
                ROW_NUMBER() OVER (PARTITION BY PSPM.MonthNum ORDER BY PSPM.Quantity DESC) AS Rank_SoldMost
            FROM
                ProductSalesPerMonth PSPM
        )
    SELECT
        PS.MonthNum,
        P.ProductName,
        PS.Quantity,
        CASE
            WHEN Rank_SoldMost = 1 THEN 'Top Seller'
            WHEN Rank_SoldLeast = 1 THEN 'Bottom Seller'
            ELSE 'Only Seller'
        END AS SalesRank
    FROM
        RankedProductSalesPerMonth PS
        JOIN Products P
        ON P.ProductID = PS.ProductID
    WHERE
        (Rank_SoldMost = 1 OR Rank_SoldLeast = 1)
    ORDER BY
        MonthNum ASC,
        Quantity DESC
    ;
    

    输出:

    MonthNum ProductName           Quantity   SalesRank 
    1        Geitost               119        Top Seller
    1        Konbu                 2          Bottom Seller
    2        Pâté chinois          180        Top Seller
    2        Gorgonzola Telino     3          Bottom Seller
    3        Raclette Courdavault  162        Top Seller
    3        Konbu                 1          Bottom Seller
    

    也许你看到这个并说“Jeezuz!”,所以这里是对代码的快速解释。

    WITH允许您组合一种称为“公用表表达式”的子查询。在SQL Server中,它应该像视图一样工作。 CTE可以互相参考。我正在使用它们,因为我认为理解各个组件要比一个大的SELECT更容易,你在任何地方引用DATEPART(MM, O.OrderDate)SUM(OD.Quantity)。它还允许我们推迟连接表(如Product),直到我们真正需要这些信息。

    我们的第一个条款按月对每个产品进行分组和汇总。就是这样。

    第二个条款确定了最高和最低卖家。在SQL Server中,从组中查找一条记录的常用方法是进行分区和排序,以便将您想要的记录冒泡到排序列表的顶部。通过按数量DESC排序,我们的畅销商将在Ranked_SoldMost列中获得“1”。底部卖家类似。

    第三个条款允许我们过滤到我们的顶部/底部卖家,然后使用产品信息装饰ProductID。

    就是这样。如果这不是你要求的,或者你有疑问,那就开火吧。

答案 1 :(得分:1)

我提出了解决问题的解决方案。 它是一个包含3个子选择的select语句,但它可以工作,并且在同一行上销售最多且销售最少的产品:

select  
    a.month,
    (select top 1 
            p.ProductName as pid 
        from Northwind.dbo.[Order Details] od1 
            left join Northwind.dbo.Orders o on  o.OrderID = od1.OrderID 
            left join Northwind.dbo.Products p on p.ProductID = od1.ProductID 
        where 
            YEAR(o.OrderDate)=1997 and 
            DATEPART(MM,o.OrderDate) = a.month 
        group by 
            p.ProductName,
            DATEPART(MM,o.OrderDate) 
        having 
            sum(od1.Quantity) = MAX(a.qty)), 
    max(a.qty) as maxQty,
    (select top 1 
            p.ProductName as pid 
        from Northwind.dbo.[Order Details] od1 
            left join Northwind.dbo.Orders o on  o.OrderID = od1.OrderID 
            left join Northwind.dbo.Products p on p.ProductID = od1.ProductID 
        where 
            YEAR(o.OrderDate)=1997 and 
            DATEPART(MM,o.OrderDate) = a.month 
        group by 
            p.ProductName,
            DATEPART(MM,o.OrderDate) 
        having 
            sum(od1.Quantity) = MIN(a.qty)), 
    min(a.qty) as minQty
from 
    (select 
            p.ProductName as pid,
            DATEPART(MM,o.OrderDate) as month, 
            sum(od1.Quantity) as qty 
        from Northwind.dbo.[Order Details] od1 
            left join Northwind.dbo.Orders o on  o.OrderID = od1.OrderID 
            left join Northwind.dbo.Products p on p.ProductID = od1.ProductID 
        where 
            YEAR(o.OrderDate)=1997 
        group by 
            p.ProductName,
            DATEPART(MM,o.OrderDate)) as a 
group by 
    a.month

我确信使用一些临时表格可以做得更聪明

答案 2 :(得分:0)

很难说出你在问什么,特别是当你没有为你的桌子提供任何模式时。但是,要开始学习SQL中的JOIN语句,我建议Jeff Atwood's Visual Guide