SQL Server:同一查询中的平均值,最大值和最小值

时间:2014-11-28 15:09:54

标签: sql-server

我有这个设置:

CREATE TABLE Stores
(
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NOT NULL
);

CREATE TABLE Agents
(
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](200) NOT NULL,
    [StoreID] [int] NULL
);

CREATE TABLE Sales
(
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [AgentID] [int] NOT NULL,
    [Value] [money] NOT NULL
);

INSERT INTO Stores(Name) VALUES ('Paris');
INSERT INTO Stores(Name) VALUES ('New York');
INSERT INTO Stores(Name) VALUES ('Tokyo');
INSERT INTO Stores(Name) VALUES ('Rio de Janeiro');

INSERT INTO Agents (Name,StoreID) VALUES ('Michel', 1);
INSERT INTO Agents (Name,StoreID) VALUES ('Didier', 1);
INSERT INTO Agents (Name,StoreID) VALUES ('Gaston', 1);
INSERT INTO Agents (Name,StoreID) VALUES ('Mark', 2);
INSERT INTO Agents (Name,StoreID) VALUES ('Ben', 2);
INSERT INTO Agents (Name,StoreID) VALUES ('James', 2);
INSERT INTO Agents (Name,StoreID) VALUES ('Natsuo',3);
INSERT INTO Agents (Name,StoreID) VALUES ('Matheus',4);

INSERT INTO Sales (AgentID,Value) VALUES (1,500);
INSERT INTO Sales (AgentID,Value) VALUES (2,100);
INSERT INTO Sales (AgentID,Value) VALUES (3,200);
INSERT INTO Sales (AgentID,Value) VALUES (4,300);
INSERT INTO Sales (AgentID,Value) VALUES (5,250);
INSERT INTO Sales (AgentID,Value) VALUES (6,400);
INSERT INTO Sales (AgentID,Value) VALUES (7,200);
INSERT INTO Sales (AgentID,Value) VALUES (8,100);
INSERT INTO Sales (AgentID,Value) VALUES (1,500);
INSERT INTO Sales (AgentID,Value) VALUES (6,800);
INSERT INTO Sales (AgentID,Value) VALUES (3,1500);
INSERT INTO Sales (AgentID,Value) VALUES (2,50);
INSERT INTO Sales (AgentID,Value) VALUES (7,789);
INSERT INTO Sales (AgentID,Value) VALUES (5,230);

对于每个Store,我希望通过一次查询获得平均销售总额,即获得最多和最少的代理商。

我知道如何使用单独的查询获取此信息,但我想使用单个查询。

这是我想要的输出:

New York       | 660 | James   | 1200 | Mark    | 300
Paris          | 950 | Gaston  | 1700 | Didier  | 150
Rio de Janeiro | 100 | Matheus |  100 | Matheus | 100
Tokyo          | 989 | Natsuo  |  989 | Natsuo  | 989

这是我到目前为止所做的:

WITH AgentStats
AS (
    SELECT Stores.NAME StoreName,
    Agents.NAME AgentName,
    SUM(Value) TotalValue
    FROM Sales
    LEFT JOIN Agents ON Agents.ID = Sales.AgentID
    LEFT JOIN Stores ON Stores.ID = Agents.StoreID
    GROUP BY Stores.NAME,
    Sales.AgentID,
    Agents.NAME
    )
SELECT StoreName,
    AVG(TotalValue),
    MAX(TotalValue),
    MIN(TotalValue)
FROM AgentStats
GROUP BY StoreName

谢谢!

3 个答案:

答案 0 :(得分:0)

这似乎有效:

;With Totals as (
    select
        s.AgentID,
        StoreID,
        SUM(Value) as TotalSales
    from
        Agents a
            inner join
        Sales s
            on
                a.ID = s.AgentID
    group by s.AgentID,
    StoreID
), Ordered as (
    select
        AgentID,
        StoreID,
        TotalSales,
        ROW_NUMBER() OVER (PARTITION BY StoreID ORDER BY TotalSales) as rnLow,
        ROW_NUMBER() OVER (PARTITION BY StoreID ORDER BY TotalSales desc) as rnHigh,
        AVG(TotalSales) OVER (PARTITION BY StoreID) as StoreAverage
    from
        Totals
)
select
    st.Name,
    o1.StoreAverage,
    a1.Name,
    o1.TotalSales,
    a2.Name,
    o2.TotalSales
from
    Stores st
        inner join
    Ordered o1
        on
            st.ID = o1.StoreID and
            o1.rnHigh = 1
        inner join
    Agents a1
        on
            o1.AgentID = a1.ID
        inner join
    Ordered o2
        on
            st.ID = o2.StoreID and
            o2.rnLow = 1
        inner join
    Agents a2
        on
            o2.AgentID = a2.ID

结果:

Name                StoreAverage          Name      TotalSales   Name     TotalSales
------------------- --------------------- --------- ------------ -------- ---------------------
Paris               950.00                Gaston    1700.00      Didier   150.00
New York            660.00                James     1200.00      Mark     300.00
Tokyo               989.00                Natsuo    989.00       Natsuo   989.00
Rio de Janeiro      100.00                Matheus   100.00       Matheus  100.00

这似乎符合您的要求。请注意,我们将其拆分为两个单独的CTE,我们首先计算单个代理总计,然后根据这些结果进行计算。

我们与ROW_NUMBER()合作,因为您不仅仅想要找到销售的MINMAX值 - 您希望找到,其中出现最小值或最大值。另外,因为我使用了ROW_NUMBER(),如果顶部或底部位置存在平局,您将获得任意结果 - 其中一行将是行号1,其他行将被忽略。如果你需要处理关系,那么我们需要更多关于关系发生时应该做什么的规范。

答案 1 :(得分:0)

您可以将Rank()函数添加到您的cte并将其加入自身:

WITH    AgentStats
          AS ( SELECT   Stores.NAME StoreName ,
                        Agents.NAME AgentName ,
                        SUM(Value) TotalValue ,
                        RANK() OVER ( PARTITION BY Stores.name ORDER BY SUM(value) DESC ) AS highest ,
                        RANK() OVER ( PARTITION BY Stores.name ORDER BY SUM(value) ) AS lowest
               FROM     Sales
                        LEFT JOIN Agents ON Agents.ID = Sales.AgentID
                        LEFT JOIN Stores ON Stores.ID = Agents.StoreID
               GROUP BY Stores.NAME ,
                        Sales.AgentID ,
                        Agents.NAME
             )
    SELECT  as1.StoreName ,
            AVG(as1.TotalValue) ,
            as2.AgentName ,
            MAX(as1.TotalValue) ,
            as3.AgentName ,
            MIN(as1.TotalValue)
    FROM    AgentStats as1
            INNER JOIN AgentStats as2 ON as1.StoreName = as2.StoreName
                                         AND as2.highest = 1
            INNER JOIN AgentStats as3 ON as1.StoreName = as3.StoreName
                                         AND as3.lowest = 1
    GROUP BY as1.StoreName ,
            as2.AgentName ,
            as3.AgentName

答案 2 :(得分:0)

当你想表达获得最多的代理时,它就是

  1. 在同一商店内 - >商店分区
  2. 谁获得了最多 - >订购销售总额
  3. 名称 - > FIRST_VALUE(AGENTNAME)
  4. 所以最终陈述是

    WITH StoreAgent AS
    (
        SELECT dbo.Stores.Name AS StoreName, dbo.Agents.Name AS AgentName, SUM(Value) AS SumOfSales
        FROM dbo.Stores
        JOIN dbo.Agents ON dbo.Stores.ID = dbo.Agents.StoreID
        JOIN dbo.Sales ON dbo.Agents.ID = dbo.Sales.AgentID
        GROUP BY dbo.Stores.Name, dbo.Agents.Name
    )
    SELECT DISTINCT StoreName, AVG(SumOfSales) OVER (PARTITION BY StoreName),
        FIRST_VALUE(AgentName) OVER (PARTITION BY StoreName ORDER BY SumOfSales DESC) AS AgentMost,
        FIRST_VALUE(SumOfSales) OVER (PARTITION BY StoreName ORDER BY SumOfSales DESC) AS Most,
        FIRST_VALUE(AgentName) OVER (PARTITION BY StoreName ORDER BY SumOfSales) AS AgentLeast,
        FIRST_VALUE(SumOfSales) OVER (PARTITION BY StoreName ORDER BY SumOfSales) AS Least
    FROM StoreAgent