需要帮助MS SQL查询。我需要在同一列中显示两个值之间的差异,其中数据在最大和最小日期之间。例如,如果我有下表:
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
提前致谢。
答案 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
分组,并计算两个值的SUM
。 CASE
表达式会更改第一个值的符号以获得差异。
如果可能只有一行的位置,则结果为负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