最大和最小日期之间同一列中的值之间的差异?

时间:2016-10-28 06:14:37

标签: sql sql-server tsql

需要帮助MS SQL查询。我需要在同一列中显示两个值之间的差异,其中数据在最大和最小日期之间。例如,如果我有下表:

see details behind the image

location|   date        |amount
------- |   -------     |-------
1000    |   2016-01-01  |400
1000    |   2016-01-04  |600    
1000    |   2016-01-05  |650
1000    |   2016-01-06  |820
1000    |   2016-01-18  |850
1000    |   2016-01-22  |900
1000    |   2016-01-28  |910
1000    |   2016-01-31  |950
2000    |   2016-01-07  |100
2000    |   2016-01-13  |150
2000    |   2016-01-15  |260
2000    |   2016-01-20  |330

输出应如下:

location|   difference
------- |   -------
1000    |   550
2000    |   230

提前致谢。

6 个答案:

答案 0 :(得分:2)

您可以如下所示:

SELECT
   location,
   MAX(Amount) - MIN(Amount) difference
FROM
  Tbl
GROUP BY
  location

更新

SELECT
    T.location,
    Maxv.Amount - Minv.Amount as difference
FROM
(
    SELECT
       location,
       MIN(date) MinDate,
       MAX(date) MaxDate
    FROM
      Tbl A 
    GROUP BY
      location
) T INNER JOIN 
Tbl Minv ON T.MinDate = Minv.date AND T.location = Minv.location INNER JOIN 
Tbl Maxv ON T.MaxDate= Maxv.date AND T.location = Maxv.location

答案 1 :(得分:1)

这是一个经典top-n-per-group问题,您不仅需要top,还需要每组bottom

在没有自联接的情况下实现它的一种标准方法是使用ROW_NUMBER。在你的情况下,将有两组数字:有序的升序和降序。

示例数据

DECLARE @T TABLE (location int, dt date, Amount int);
INSERT INTO @T (location, dt, Amount ) VALUES
(1000,'2016-01-01',400),
(1000,'2016-01-04',600),
(1000,'2016-01-05',650),
(1000,'2016-01-06',820),
(1000,'2016-01-18',850),
(1000,'2016-01-22',900),
(1000,'2016-01-28',910),
(1000,'2016-01-31',950),
(2000,'2016-01-07',100),
(2000,'2016-01-13',150),
(2000,'2016-01-15',260),
(2000,'2016-01-20',330);

<强>查询

WITH
CTE
AS
(
    SELECT
        location
        ,dt
        ,Amount
        ,ROW_NUMBER() OVER (PARTITION BY location ORDER BY dt ASC) AS rnAsc
        ,ROW_NUMBER() OVER (PARTITION BY location ORDER BY dt DESC) AS rnDesc
    FROM @T
)
SELECT
    location
    ,SUM(CASE WHEN rnAsc = 1 THEN -Amount ELSE Amount END) AS diff
FROM CTE
WHERE
    rnAsc = 1
    OR rnDesc = 1
GROUP BY location
ORDER BY location;

<强>结果

+----------+------+
| location | diff |
+----------+------+
|     1000 |  550 |
|     2000 |  230 |
+----------+------+

要了解它是如何工作的,首先只运行CTE中的查询并检查中间结果。

主要查询只按location分组,并计算两个值的SUMCASE表达式会更改第一个值的符号以获得差异。

如果可能只有一行的位置,则结果为负Amount。好像它是0和唯一可用的Amount值之间的差异。如果您想在这种情况下获得其他结果,请澄清问题。

答案 2 :(得分:0)

BEGIN TRAN

CREATE TABLE #Details(_Location VARCHAR(100),_Date DATE,Amount INT)
CREATE TABLE #Diff(Location VARCHAR(100),_MinDate DATE,_MaxDate DATE,Amount1 INT,Amount2 INT)

INSERT INTO #Details(_Location ,_Date ,Amount )
SELECT 1000,'2016-01-01',400 UNION ALL
SELECT 1000,'2016-01-04',600 UNION ALL
SELECT 1000,'2016-01-05',650 UNION ALL
SELECT 1000,'2016-01-06',820 UNION ALL
SELECT 1000,'2016-01-18',850 UNION ALL
SELECT 1000,'2016-01-22',900 UNION ALL
SELECT 1000,'2016-01-28',910 UNION ALL
SELECT 1000,'2016-01-31',950 UNION ALL
SELECT 2000,'2016-01-07',100 UNION ALL
SELECT 2000,'2016-01-13',150 UNION ALL
SELECT 2000,'2016-01-15',260 UNION ALL
SELECT 2000,'2016-01-20',330 


INSERT INTO  #Diff (Location ,_MinDate ,_MaxDate)
SELECT _Location , MIN(_Date) _MinDate, MAX(_Date) _MaxDate
FROM #Details
GROUP BY _Location


UPDATE #Diff SET Amount1 = Amount
FROM #Details
WHERE _Date = _MaxDate AND _Location = Location

UPDATE #Diff SET Amount2 = Amount
FROM #Details
WHERE _Date = _MinDate AND _Location = Location

SELECT Location , ( Amount1 - Amount2 ) [Difference]
FROM #Diff

ROLLBACK TRAN

答案 3 :(得分:0)

试试这个:

简单&amp;简短查询:

DECLARE @loc_tbl TABLE( location INT, loc_date DATE,amount INT)
INSERT INTO @loc_tbl VALUES('1000','2016-01-01','400'),
('1000','2016-01-04','600'),('1000','2016-01-05','650'),
('1000','2016-01-06','820'),('1000','2016-01-18','850'),
('1000','2016-01-22','900'),('1000','2016-01-28','910'),
('1000','2016-01-31','950'),('2000','2016-01-07','100'),
('2000','2016-01-13','150'),('2000','2016-01-15','260'),
('2000','2016-01-20','330')

SELECT A.location,(B.amount-C.amount) amt_difference FROM ( SELECT location,
MAX(loc_Date) maximum,MIN(loc_Date) minimum FROM @loc_tbl GROUP BY location ) A
LEFT JOIN @loc_tbl B ON B.loc_date = A.maximum
LEFT JOIN @loc_tbl C ON C.loc_date = A.minimum

答案 4 :(得分:0)

下面是表格(名称:MyTab)

  Location  dt      amount
    1000    2014-06-01  90
    1000    2014-09-01  40
    1000    2014-10-01  100
    1000    2015-06-01  900
    1000    2015-12-01  907
    2000    2004-11-22  432
    2000    2010-11-22  709
    2000    2014-11-01  922
    2000    2014-11-22  728
    2000    2015-11-01  907
    2000    2015-12-01  907
    2000    2016-11-22  553

以下是查询

;WITH CTE
AS(
SELECT location,min(dt) mindt,max(dt) maxdt from MyTab group by location
)
SELECT c.location,max(m.amount)-min(m.amount) amt from cte c 
INNER JOIN MyTab m on c.location = m.location and (c.mindt = m.dt or c.maxdt = m.dt )
GROUP BY c.location 

输出

location amt
1000    817
2000    121

答案 5 :(得分:0)

DECLARE @T TABLE (location int, dt date, Amount int);
INSERT INTO @T (location, dt, Amount ) VALUES
(1000,'2016-01-01',400),
(1000,'2016-01-04',600),
(1000,'2016-01-05',650),
(1000,'2016-01-06',820),
(1000,'2016-01-18',850),
(1000,'2016-01-22',900),
(1000,'2016-01-28',910),
(1000,'2016-01-31',950),
(2000,'2016-01-07',100),
(2000,'2016-01-13',150),
(2000,'2016-01-15',260),
(2000,'2016-01-20',540);


 with cte as (select location,first_value (amount)OVER(partition by location order by dt desc)v1
,last_value(amount) OVER (partition by location order by (select NULL))as v2
from @T
)
select distinct(location),v1-v2 from cte