Reputation: 21
I have a historical table XY
with these contents:
ID Person_ID Balance_on_account ts
---- ----------- -------------------- ----------
01 05 +10 10.10.14
02 05 -10 20.10.14
03 05 -50 30.10.14
04 05 +50 30.10.14
05 05 -10 30.10.14
06 06 11 11.10.14
07 06 -40 15.10.14
08 06 +5 16.10.14
09 06 -10 30.10.14
and I need to create an SQL query which will give me those Person_ID
's and timestamps where are
Balance_on_account
is negative - that's the easy one,Balance_on_account
followed by a positive number.Like for Person_ID = 05
I would have the row with ID = 05
, and for Person_ID = 06
the row with ID = 09
.
Upvotes: 1
Views: 19554
Reputation: 1848
I never used it, but you could try analytic LEAD function
SELECT *
FROM (
SELECT ID, Person_ID, Balance_on_account, ts
LEAD (Balance_on_account, 1)
OVER (PARTITION BY Person_ID ORDER BY ID) next_balance
FROM XY)
WHERE Balance_on_account < 0 and next_balance >= 0
ORDER BY ID
LEAD lets you access the following rows in a query without joining with itself. PARTITION BY groups rows by Person_ID so it doesn't mix different person's balances and ORDER BY defines the order within each group. The filtering cannot be done in the inner query because it'd filter out the rows with positive balance.
next_balance will be null for the last row.
source analytic functions and LEAD
Upvotes: 2
Reputation: 2139
The following query should give you the expected results provided the database platform you are using supports Common Table Expressions
and Window Functions
e.g. SQL Server 2008 and up.
WITH TsOrder AS
(
SELECT
Id
, Person_Id
, Balance_on_account
, ts
, ROW_NUMBER() OVER(PARTITION BY Person_Id
ORDER BY ts, Id) AS ts_Order
FROM
[TableName]
)
SELECT
*
FROM
TsOrder
LEFT JOIN TsOrder AS NextTs
ON TsOrder.Person_id = NextTs.Person_Id
AND TsOrder.ts_order = NextTs.ts_order - 1
WHERE
TsOrder.Balance_on_account < 0
AND NextTs.Balance_on_account > 0
Upvotes: 0