我试图看到基于百分比的成本增加。数据看起来像这样
ID Date Amount
123 5/1/2017 500
123 6/1/2017 500
123 7/1/2017 500
123 8/1/2017 1200
123 9/1/2017 1200
456 5/1/2017 400
456 6/1/2017 450
456 7/1/2017 450
789 5/1/2017 600
789 6/1/2017 600
789 7/1/2017 900
我想要做的是找到金额增加预定金额(50%或500)并且我想拉出先前金额的记录和新金额。结果应如下所示
ID Date Amount
123 7/1/2017 500
123 8/1/2017 1200
789 6/1/2017 600
789 7/1/2017 900
有数百万行,日期可能会有所不同,因此无法进行小型临时表解决方案。
我不知道如何开始这样的事情。我正在使用TSQL
答案 0 :(得分:1)
如果您的SQL Server版本支持lag
和lead
,请使用
select id,date,amount
from (
select t.*,
case when amount-lag(amount) over(partition by id order by date) >= 500 or
100.0*(amount-lag(amount) over(partition by id order by date))/lag(amount) over(partition by id order by date) >= 50 or
lead(amount) over(partition by id order by date)-amount >= 500 or
100.0*(lead(amount) over(partition by id order by date)-amount)/amount >= 50
then 1 else 0 end as to_select
from tbl t
) t
where to_select = 1
答案 1 :(得分:1)
这不优雅,但它应该让你去......
SELECT ID, MyDate, amount
FROM (
SELECT
MAX(Amount) OVER(PARTITION BY ID ORDER BY MyDate ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS PrevAmount,
MAX(Amount) OVER(PARTITION BY ID ORDER BY MyDate ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING) AS NextAmount,
amount,
Id,
MyDate
FROM (
SELECT 123 AS Id, CURRENT_DATE AS MyDate, 500 AS amount UNION ALL
SELECT 123 AS Id, CURRENT_DATE + INTERVAL '1' DAY AS MyDate, 1200 AS amount UNION ALL
SELECT 123 AS Id, CURRENT_DATE + INTERVAL '2' DAY AS MyDate, 1600 AS amount
) src
) src
WHERE
CASE
WHEN
(
((PrevAmount - Amount) *100) / PrevAmount >= 50 OR (Amount - PrevAmount) >= 500
) OR
(
((Amount - NextAmount) *100) / Amount >= 50 OR (NextAmount- Amount) >= 500
)
THEN 'Y'
ELSE 'N'
END = 'Y'
答案 2 :(得分:1)
对于SQL 2008版本(没有LAG和LEAD)。 您可以使用临时表而不是CTE,它可以提高工作效率。
DECLARE @table TABLE
(
Id INT,
[Date] DATETIME,
Amount INT
)
INSERT INTO @table(Id, [Date], Amount) VALUES
(123, '5/1/2017', 500),
(123, '6/1/2017', 500),
(123, '7/1/2017', 500),
(123, '8/1/2017', 1200),
(123, '9/1/2017', 1200),
(456, '5/1/2017', 400),
(456, '6/1/2017', 450),
(456, '7/1/2017', 450),
(789, '5/1/2017', 600),
(789, '6/1/2017', 600),
(789, '7/1/2017', 900)
;WITH cte AS
(
SELECT
ROW_NUMBER() OVER(PARTITION BY Id ORDER BY [Date]) AS RowNumber,
*
FROM @table
)
SELECT
CASE WHEN i.number = 1 THEN t.Id1 ELSE t.Id2 END AS Id,
CASE WHEN i.number = 1 THEN t.Date1 ELSE t.Date2 END AS [Date],
CASE WHEN i.number = 1 THEN t.Amount1 ELSE t.Amount2 END AS Amount
FROM
(
SELECT
t1.Id AS Id1,
t1.[Date] AS Date1,
t1.Amount AS Amount1,
t2.Id AS Id2,
t2.[Date] AS Date2,
t2.Amount AS Amount2
FROM cte AS t1
INNER JOIN cte AS t2 ON t2.Id = t1.Id AND t2.RowNumber = t1.RowNumber + 1
WHERE t2.Amount >= t1.Amount * 1.5 OR t2.Amount >= t1.Amount + 500 -- either 50% or 500
) AS t
CROSS JOIN
(
SELECT 1 AS number
UNION ALL SELECT 2
) AS i
ORDER BY Id, [Date]
输出:
Id Date Amount
123 2017-07-01 00:00:00.000 500
123 2017-08-01 00:00:00.000 1200
789 2017-06-01 00:00:00.000 600
789 2017-07-01 00:00:00.000 900
答案 3 :(得分:0)
您可以使用lead()
和lag()
:
select t.*
from (select t.*,
lag(amount) over (partition by id order by date) as prev_amount,
lead(amount) over (partition by id order by date) as next_amount
from t
) t
where (amount - prev_amount) > 500 or
(next_amount - amount) > 500 or
amount > prev_amount * 1.5 or
next_amount > amount * 1.5;
答案 4 :(得分:0)
不知道“百万行”:
DML:
select
t1.id ,
t1.date,
t1.amount,
t2.date as t2date,
t2.amount as t2amount,
abs(t1.amount-t2.amount) as changeTotal, -- you might want to keep the sign
(abs(t1.amount-t2.amount) / (t1.amount / 100.0))
as changePercent
from TT as t1
join TT as t2 on t1.id = t2.id
where t1.date < t2.date -- only join lesser to greater
and not exists( -- only if directly following each other
select 1
from tt as o
where o.id = t1.id
and o.date > t1.date
and o.date < t2.date
) -- output only if there is no other one between t1 and t2
输出(手动剥离空白时间):
id date amount t2date t2amount changeTotal changePercent
123 2017-05-01 500 2017-06-01 500 0 0
123 2017-06-01 500 2017-07-01 500 0 0
123 2017-07-01 500 2017-08-01 1200 700 140
123 2017-08-01 1200 2017-09-01 1200 0 0
456 2017-05-01 400 2017-06-01 450 50 12.5
456 2017-06-01 450 2017-07-01 450 0 0
789 2017-05-01 600 2017-06-01 600 0 0
789 2017-06-01 600 2017-07-01 900 300 50
DDL:
CREATE TABLE TT ("ID" int, "Date" datetime, "Amount" int);
INSERT INTO TT
(ID, Date, Amount)
VALUES
(123, '2017-05-01 00:00:00', 500),
(123, '2017-06-01 00:00:00', 500),
(123, '2017-07-01 00:00:00', 500),
(123, '2017-08-01 00:00:00', 1200),
(123, '2017-09-01 00:00:00', 1200),
(456, '2017-05-01 00:00:00', 400),
(456, '2017-06-01 00:00:00', 450),
(456, '2017-07-01 00:00:00', 450),
(789, '2017-05-01 00:00:00', 600),
(789, '2017-06-01 00:00:00', 600),
(789, '2017-07-01 00:00:00', 900)
;