sql查询查找具有最大差异的项目

时间:2013-12-06 20:15:36

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

我有我的数据库表 ABC ,如下所示:

  ItemId  Month  Year    Sales
   1        1     2013    333
   1        2     2013    454
   2        1     2013     434

等等。

我想写一个查询来查找从上个月到本月销售额增幅最高的前3个项目,以便我在输出中看到类似的内容。     输出:

 ItemId    IncreaseInSales
  1               +121
  9                +33
  6                +16    

我来到这里:

select 

 (select Sum(Sales) from ABC where [MONTH] = 11  )
 -
 (select Sum(Sales) from ABC where [MONTH] = 10) 

我不能使用组,因为它给出了错误。任何人都可以指出我的方式   继续前进?

7 个答案:

答案 0 :(得分:1)

假设您希望增加给定月份,您还可以使用聚合查询执行此操作:

select top 3 a.ItemId,
       ((sum(case when year = @YEAR and month = @MONTH then 1.0*sales end) /
         sum(case when year = @YEAR and month = @MONTH - 1 or
                       year = @YEAR - 1 and @Month = 1 and month = 12
                  then sales end)
        ) - 1
       ) * 100 as pct_increase
from ABC a
group by a.ItemId
order by pct_increase desc;

您可以将您关心的年/月组合放在变量@YEAR@MONTH中。

编辑:

如果你只是想要增加,那么就要有所作为:

select top 3 a.ItemId,
       (sum(case when year = @YEAR and month = @MONTH then 1.0*sales end) -
        sum(case when year = @YEAR and month = @MONTH - 1 or
                      year = @YEAR - 1 and @Month = 1 and month = 12
                 then sales
            end)
       ) as difference
from ABC a
group by a.ItemId
order by difference desc;

答案 1 :(得分:0)

以下是演示以下查询的 SQL Fiddle

SELECT TOP(3) NewMonth.ItemId, 
  NewMonth.Month11Sales - OldMonth.Month10Sales AS IncreaseInSales
FROM 
(
  SELECT s1.ItemId, Sum(s1.Sales) AS Month11Sales
  FROM ABC AS s1
  WHERE s1.MONTH = 11
  AND s1.YEAR = 2013
  GROUP BY s1.ItemId
) AS NewMonth
INNER JOIN 
(
  SELECT s2.ItemId, Sum(s2.Sales)  AS Month10Sales
  FROM ABC AS s2
  WHERE s2.MONTH = 10
  AND s2.YEAR = 2013 
  GROUP BY s2.ItemId
) AS OldMonth
ON NewMonth.ItemId = OldMonth.ItemId
ORDER BY NewMonth.Month11Sales - OldMonth.Month10Sales DESC

你从来没有提到过ItemId是否有多个Month的记录,所以我提出了查询来处理它。显然,您的查询中缺少year = 2013。一旦你过了今年,你将需要它。

答案 2 :(得分:0)

您的示例数据似乎不完整,但是,这是我的尝试。我假设你想知道从一个月到下一个月销售差异最大的三个项目:

WITH Increases AS
(
    SELECT a1.itemid, 
           a1.sales - (SELECT a2.sales 
                       FROM   dbo.abc a2 
                       WHERE  a1.itemid = a2.itemid 
                          AND ( ( a1.year = a2.year 
                                  AND a1.month > 1 
                                  AND a1.month = a2.month + 1 ) 
                                 OR ( a1.year = a2.year + 1 
                                      AND a1.month = 1 
                                      AND a2.month = 12 ) ))AS IncreaseInSales 
    FROM   dbo.abc a1 
)
SELECT TOP 3 ItemID, MAX(IncreaseInSales) AS IncreaseInSales 
FROM Increases
GROUP BY ItemID
ORDER BY MAX(IncreaseInSales) DESC

Demo

答案 3 :(得分:0)

我这样做。它应该适用于所有标记的SQL Server版本:

SELECT TOP 3 [ItemId],
  MAX(CASE WHEN [Month] = 2 THEN [Sales] END) -
  MAX(CASE WHEN [Month] = 1 THEN [Sales] END) [Diff]
FROM t
WHERE [Month] IN (1, 2) AND [Year] = 2013
GROUP BY [ItemId]
HAVING COUNT(*) = 2
ORDER BY [Diff] DESC

小提琴here

我添加HAVING子句的原因是,如果只在其中一个月内添加任何项目,则数字将全部错误。所以我只是比较两个月才出现的项目。

WHERE子句的原因是只提前过滤所需的月份并提高查询效率。

SQL Server 2012解决方案也可以是:

SELECT TOP 3 [ItemId], [Diff] FROM (
  SELECT [ItemId],
    LEAD([Sales]) OVER (PARTITION BY [ItemId] ORDER BY [Month]) - [Sales] Diff
  FROM t
  WHERE [Month] IN (1, 2) AND [Year] = 2013
) s
WHERE [Diff] IS NOT NULL
ORDER BY [Diff] DESC

答案 4 :(得分:0)

另一种选择可能就是这些问题:

SELECT top 3 a.itemid, asales-bsales increase FROM
(
(select itemid, month, sum(sales) over(partition by itemid) asales from ABC where month=2
 and year=2013) a  
INNER JOIN
(select itemid, month, sum(sales) over(partition by itemid) bsales from ABC where month=1 
 and year=2013) b
ON a.itemid=b.itemid
 ) 
ORDER BY increase desc

如果您需要在没有销售的情况下满足数月,那么您可以进行全加入并计算增加为isnull(asales,0) - isnull(bsales,0)

答案 5 :(得分:0)

您可以根据PIVOT运算符调整此解决方案:

SET NOCOUNT ON;

DECLARE @Sales TABLE
(
    ItemID  INT NOT NULL,
    SalesDate DATE NOT NULL,
    Amount  MONEY NOT NULL
);
INSERT  @Sales (ItemID, SalesDate, Amount) 
VALUES 
(1, '2013-01-15', 333), (1, '2013-01-14', 111), (1, '2012-12-13', 100), (1, '2012-11-12', 150),
(2, '2013-01-11', 200), (2, '2012-12-10', 150), (3, '2013-01-09', 900);

-- Parameters (current year & month)
DECLARE @pYear SMALLINT = 2013, 
        @pMonth TINYINT = 1;

DECLARE @FirstDayOfCurrentMonth DATE = CONVERT(DATE, CONVERT(CHAR(4), @pYear) + '-' + CONVERT(CHAR(2), @pMonth) + '-01');

DECLARE @StartDate DATE = DATEADD(MONTH, -1, @FirstDayOfCurrentMonth), -- Begining of the previous month
        @EndDate DATE = DATEADD(DAY, -1, DATEADD(MONTH, 1, @FirstDayOfCurrentMonth)) -- End of the current month

SELECT  TOP(3) t.ItemID, 
        t.[2]-t.[1] AS IncreaseAmount
FROM
(
    SELECT  y.ItemID, y.Amount,
            DENSE_RANK() OVER(ORDER BY y.FirstDayOfSalesMonth ASC) AS MonthNum -- 1=Previous Month, 2=Current Month
    FROM
    (
        SELECT  x.ItemID, x.Amount,
                DATEADD(MONTH, DATEDIFF(MONTH, 0, x.SalesDate), 0) AS FirstDayOfSalesMonth
        FROM    @Sales x
        WHERE   x.SalesDate BETWEEN @StartDate AND @EndDate
    ) y
) z
PIVOT( SUM(z.Amount) FOR z.MonthNum IN ([1], [2]) ) t
ORDER BY IncreaseAmount DESC;

SQLFiddle demo

答案 6 :(得分:0)

SELECT
  cur.[ItemId]
  MAX(nxt.[Sales] - cur.[Sales]) AS [IncreaseInSales]
FROM ABC cur
INNER JOIN ABC nxt ON (
  nxt.[Year]  = cur.[Year] + cur.[month]/12 AND
  nxt.[Month] = cur.[Month]%12 + 1
)
GROUP BY cur.[ItemId]