使用最昂贵的订单获取客户的名称

时间:2012-05-16 07:21:57

标签: sql-server sql-server-2008-r2

我有一个包含4个表的小型数据库:客户 - 订单 - OrderLine - 产品,我正在玩一些查询,并试图获取最昂贵订单的人的名字。

经过一些游戏后,我想出了以下查询,其中显示了所有订单的价格:

SELECT SUM(OrderLine.Amount * Product.Price) AS OrderLinePrice, Orders.Id, Customer.Lastname
FROM OrderLine, Product, Orders, Customer
WHERE OrderLine.ProductId = Product.Id
AND Orders.Id = OrderLine.OrderId
AND Customer.Id = Orders.CustomerId
GROUP BY Orders.Id, Customer.Lastname
ORDER BY OrderLinePrice DESC

现在我在概念上需要做的,或者我认为我需要做的是,应用MAX()来只选择最高的OrderLinePrice,但是我没有成功,因为SQL Server抱怨无法执行聚合函数包含聚合的表达式......

===============更新:

目前我的查询如下:

SELECT t.CustomerLastName
FROM (
    SELECT SUM(OrderLine.Amount * Product.Price) AS OrderLinePrice, Orders.Id, Customer.Lastname AS CustomerLastName
    FROM OrderLine, Product, Orders, Customer
    WHERE OrderLine.ProductId = Product.Id
    AND Orders.Id = OrderLine.OrderId
    AND Customer.Id = Orders.CustomerId
    GROUP BY Orders.Id, Customer.Lastname
    ) AS t
WHERE t.OrderLinePrice = 
(
    SELECT MAX(s.OrderLinePrice) AS MaxOrderPrice
    FROM (
        SELECT SUM(OrderLine.Amount * Product.Price) AS OrderLinePrice, Orders.Id, Customer.Lastname AS CustomerLastName
        FROM OrderLine, Product, Orders, Customer
        WHERE OrderLine.ProductId = Product.Id
        AND Orders.Id = OrderLine.OrderId
        AND Customer.Id = Orders.CustomerId
        GROUP BY Orders.Id, Customer.Lastname
        ) AS s
)
ORDER BY CustomerLastName

这将检索客户列表,其订单价格等于最昂贵订单的价格。这确切地检索了我想要的东西,但感觉非常多余。

我应该如何开始提高效率(如果可能的话)?

2 个答案:

答案 0 :(得分:2)

您可以通过多种方式完成此操作。以下是一些建议:

<强> CTE

;WITH CTE
AS
(
    SELECT SUM(OrderLine.Amount * Product.Price) AS OrderLinePrice, 
    Orders.Id, Customer.Lastname
    FROM OrderLine, Product, Orders, Customer
    WHERE OrderLine.ProductId = Product.Id
    AND Orders.Id = OrderLine.OrderId
    AND Customer.Id = Orders.CustomerId
    GROUP BY Orders.Id, Customer.Lastname
)
SELECT
    MAX(OrderLinePrice) AS MaxorderPrice
FROM
    CTE

子查询,最大

SELECT
    MAX(t.OrderLinePrice) AS MaxorderPrice
FROM
    (
        SELECT SUM(OrderLine.Amount * Product.Price) AS OrderLinePrice, 
            Orders.Id, Customer.Lastname
        FROM OrderLine, Product, Orders, Customer
        WHERE OrderLine.ProductId = Product.Id
        AND Orders.Id = OrderLine.OrderId
        AND Customer.Id = Orders.CustomerId
        GROUP BY Orders.Id, Customer.Lastname
    ) AS t

按订单排名第一

SELECT TOP 1
    t.Amount
FROM
    (
        SELECT SUM(OrderLine.Amount * Product.Price) AS OrderLinePrice, 
            Orders.Id, Customer.Lastname
        FROM OrderLine, Product, Orders, Customer
        WHERE OrderLine.ProductId = Product.Id
        AND Orders.Id = OrderLine.OrderId
        AND Customer.Id = Orders.CustomerId
        GROUP BY Orders.Id, Customer.Lastname
    ) AS t
ORDER BY t.OrderLinePrice DESC

修改

也许是这样的:

;WITH CTE
AS
(
    SELECT SUM(OrderLine.Amount * Product.Price) AS OrderLinePrice, 
    Orders.Id, Customer.Lastname
    FROM OrderLine, Product, Orders, Customer
    WHERE OrderLine.ProductId = Product.Id
    AND Orders.Id = OrderLine.OrderId
    AND Customer.Id = Orders.CustomerId
    GROUP BY Orders.Id, Customer.Lastname
)
SELECT
    *
FROM
    CTE
WHERE 
    CTE.OrderLinePrice=(SELECT MAX(CTE2.OrderLinePrice) FROM CTE AS CTE2)

或者,如果您想要max by customer姓氏。你可以这样做:

;WITH CTE
AS
(
    SELECT SUM(OrderLine.Amount * Product.Price) AS OrderLinePrice, 
    Orders.Id, Customer.Lastname
    FROM OrderLine, Product, Orders, Customer
    WHERE OrderLine.ProductId = Product.Id
    AND Orders.Id = OrderLine.OrderId
    AND Customer.Id = Orders.CustomerId
    GROUP BY Orders.Id, Customer.Lastname
)
SELECT
    MAX(OrderLinePrice) AS MaxPrice,
    Lastname
FROM
    CTE
GROUP BY 
    CTE.Lastname

答案 1 :(得分:1)

首先,您是否考虑过使用显式连接?它可能只是一个品味问题,但也许您会发现显式连接的查询比隐式连接(或“逗号”连接)更清晰,就像在您的示例中一样。

至于问题,您可以使用TOP (1) WITH TIES,如下所示:

WITH ranked AS (
  SELECT
    SUM(ol.Amount * p.Price) AS OrderLinePrice,
    o.Id,
    c.Lastname AS CustomerLastName
  FROM OrderLine ol
    INNER JOIN Product  p ON p.Id = ol.ProductId
    INNER JOIN Orders   o ON o.Id = ol.OrderId
    INNER JOIN Customer c ON c.Id = o.CustomerId
  GROUP BY Orders.Id, Customer.Lastname
)
SELECT *
FROM (
  SELECT TOP (1) WITH TIES CustomerLastName
  FROM ranked
  ORDER BY OrderLinePrice DESC
) s
ORDER BY CustomerLastName

或者您可以使用RANK()DENSE_RANK(),如下所示:

WITH ranked AS (
  SELECT
    SUM(ol.Amount * p.Price) AS OrderLinePrice,
    o.Id,
    c.Lastname AS CustomerLastName,
    RANK() OVER (ORDER BY SUM(ol.Amount * p.Price) DESC) AS rnk
  FROM OrderLine ol
    INNER JOIN Product  p ON p.Id = ol.ProductId
    INNER JOIN Orders   o ON o.Id = ol.OrderId
    INNER JOIN Customer c ON c.Id = o.CustomerId
  GROUP BY Orders.Id, Customer.Lastname
)
SELECT CustomerLastName
FROM ranked
WHERE rnk = 1
ORDER BY CustomerLastName

如果您只对最高价格感兴趣,RANK()就足够了,但如果您希望客户获得最高 n 总计,请使用DENSE_RANK()相反,将条件从rnk = 1更改为rnk <= n