Extract Data by comparing 4 different rows

孤街醉人 提交于 2019-12-10 23:58:43

问题


The Table data is as below, need to extract records that met the below conditions

Here Value = Value2-Value1

    Value of two days back data should be > 2
    Value of last day  data is < 0
    Value of next day data is < 4 and >0
    Value of after next day data > 4

All the dates are weekdays,if any date falls on friday, need to compare with next day ie.. Monday. and comparision is with alternative days only

from below output have to be.

1         4-1-2018   15          18
2         3-1-2018    3           0 


    -----------------------------------
    code      Date      Value1      Value2
    ---------------------------------------
    1         1-1-2018   13          14
    1         2-1-2018   14          18
    1         3-1-2018   15          11
    1         4-1-2018   15          18
    1         5-1-2018   15          18
    1         6-1-2018   11          18
    1         7-1-2018   15          18
    2         1-1-2019    1           3
    2         2-1-2018    2           5
    2         3-1-2018    3           0
    2         4-1-2018    3           7
    2         5-1-2018    3           4
    2         6-1-2018    3           9
    2         7-1-2018    3           7

I am pretty much confused at comparing multiple rows, any help is greatly appreciated.


回答1:


Starting with v2012 we have support for LAG() and LEAD(). Try this out:

SET DATEFORMAT dmy;

DECLARE @tbl TABLE(code INT,[Date] DATE,Value1 INT,Value2 INT);
INSERT INTO @tbl VALUES
 (1,'1-1-2018',13,14)
,(1,'2-1-2018',14,18)
,(1,'3-1-2018',15,11)
,(1,'4-1-2018',15,18)
,(1,'5-1-2018',15,18)
,(1,'6-1-2018',11,18)
,(1,'7-1-2018',15,18)
,(2,'1-1-2019', 1, 3)
,(2,'2-1-2018', 2, 5)
,(2,'3-1-2018', 3, 0)
,(2,'4-1-2018', 3, 7)
,(2,'5-1-2018', 3, 4)
,(2,'6-1-2018', 3, 9)
,(2,'7-1-2018', 3, 7);


WITH cte AS
(
    SELECT *
          ,LAG(Value2-Value1,2) OVER(PARTITION BY code ORDER BY [Date]) TwoDaysBack
          ,LAG(Value2-Value1,1) OVER(PARTITION BY code ORDER BY [Date]) Yesterday
          ,LEAD(Value2-Value1,1) OVER(PARTITION BY code ORDER BY [Date]) tomorrow
          ,LEAD(Value2-Value1,2) OVER(PARTITION BY code ORDER BY [Date]) TwoDaysAhead
    FROM @tbl 
)
SELECT *
FROM cte;

I do not really understand, how you want to use these values in a filter to get the expected output. If you need help with this, just come back...

The result

+------+------------+--------+--------+-------------+-----------+----------+--------------+
| code | Date       | Value1 | Value2 | TwoDaysBack | Yesterday | tomorrow | TwoDaysAhead |
+------+------------+--------+--------+-------------+-----------+----------+--------------+
| 1    | 2018-01-01 | 13     | 14     | NULL        | NULL      | 4        | -4           |
+------+------------+--------+--------+-------------+-----------+----------+--------------+
| 1    | 2018-01-02 | 14     | 18     | NULL        | 1         | -4       | 3            |
+------+------------+--------+--------+-------------+-----------+----------+--------------+
| 1    | 2018-01-03 | 15     | 11     | 1           | 4         | 3        | 3            |
+------+------------+--------+--------+-------------+-----------+----------+--------------+
| 1    | 2018-01-04 | 15     | 18     | 4           | -4        | 3        | 7            |
+------+------------+--------+--------+-------------+-----------+----------+--------------+
| 1    | 2018-01-05 | 15     | 18     | -4          | 3         | 7        | 3            |
+------+------------+--------+--------+-------------+-----------+----------+--------------+
| 1    | 2018-01-06 | 11     | 18     | 3           | 3         | 3        | NULL         |
+------+------------+--------+--------+-------------+-----------+----------+--------------+
| 1    | 2018-01-07 | 15     | 18     | 3           | 7         | NULL     | NULL         |
+------+------------+--------+--------+-------------+-----------+----------+--------------+
| 2    | 2018-01-02 | 2      | 5      | NULL        | NULL      | -3       | 4            |
+------+------------+--------+--------+-------------+-----------+----------+--------------+
| 2    | 2018-01-03 | 3      | 0      | NULL        | 3         | 4        | 1            |
+------+------------+--------+--------+-------------+-----------+----------+--------------+
| 2    | 2018-01-04 | 3      | 7      | 3           | -3        | 1        | 6            |
+------+------------+--------+--------+-------------+-----------+----------+--------------+
| 2    | 2018-01-05 | 3      | 4      | -3          | 4         | 6        | 4            |
+------+------------+--------+--------+-------------+-----------+----------+--------------+
| 2    | 2018-01-06 | 3      | 9      | 4           | 1         | 4        | 2            |
+------+------------+--------+--------+-------------+-----------+----------+--------------+
| 2    | 2018-01-07 | 3      | 7      | 1           | 6         | 2        | NULL         |
+------+------------+--------+--------+-------------+-----------+----------+--------------+
| 2    | 2019-01-01 | 1      | 3      | 6           | 4         | NULL     | NULL         |
+------+------------+--------+--------+-------------+-----------+----------+--------------+

The idea in short:

Both, LAG() and LEAD() take an argument for the needed value, a second, how many rowswe want to skip, and as a third argument a default value you might specify to avoid NULLs in the result, when there is no row in scope.

The OVER() clause will tell any windowing function if we want to think of the set as divided in groups and the sort order (otherwise the system would not know what is leading or lagging.




回答2:


With lead and lag window functions:

with cte as (
  select *,
    lag(value2 - value1, 2) over (partition by code order by date) prev2,
    lag(value2 - value1, 1) over (partition by code order by date) prev1,
    lead(value2 - value1, 1) over (partition by code order by date) next1,
    lead(value2 - value1, 2) over (partition by code order by date) next2
  from tablename
)
select code, date, value1, value2
from cte 
where prev2 > 2 and prev1 < 0 and next1 > 0 and next1 < 4 and next2 > 4

See the demo.
Results:

code | date                | value1 | value2
---: | :------------------ | -----: | -----:
   1 | 01/04/2018 00:00:00 |     15 |     18
   2 | 01/04/2018 00:00:00 |      3 |      7

There is a difference between your expected results for code = 2 and my results, so check its validity.



来源:https://stackoverflow.com/questions/57823188/extract-data-by-comparing-4-different-rows

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!