Home > Software engineering >  A query that compares the LAG value and fills the sub column with data if there is a difference?
A query that compares the LAG value and fills the sub column with data if there is a difference?

Time:12-02

A query that compares the LAG value and fills the sub column with data if there is a difference?

WITH A AS (
    SELECT 'GOLD' AS Title, 1 AS RNUM, 555.4 AS VALUE1, null AS DIFF, null AS LAG FROM DUAL UNION ALL
    SELECT 'GOLD' AS Title, 2 AS RNUM, 555.4 AS VALUE1, 0 AS DIFF, 555.4 AS LAG FROM DUAL UNION ALL
SELECT 'GOLD' AS Title, 3 AS RNUM, 555.4 AS VALUE1, 0 AS DIFF, 555.4 AS LAG FROM DUAL UNION ALL
 SELECT 'GOLD' AS Title, 4 AS RNUM, 556 AS VALUE1, 0.6 AS DIFF, 555.4 AS LAG FROM DUAL UNION ALL
SELECT 'GOLD' AS Title, 5 AS RNUM, 556 AS VALUE1, 0 AS DIFF, 556 AS LAG FROM DUAL UNION ALL
SELECT 'GOLD' AS Title, 6 AS RNUM, 556 AS VALUE1, 0 AS DIFF, 556 AS LAG FROM DUAL UNION ALL
SELECT 'GOLD' AS Title, 7 AS RNUM, 556.7 AS VALUE1, 0.7 AS DIFF, 556 AS LAG FROM DUAL UNION ALL
SELECT 'GOLD' AS Title, 8 AS RNUM, 556.7 AS VALUE1, 0 AS DIFF,556.7 AS LAG FROM DUAL UNION ALL
SELECT 'GOLD' AS Title, 9 AS RNUM, 557.3 AS VALUE1, 0.6 AS DIFF, 556.7 AS LAG FROM DUAL UNION ALL
SELECT 'SILVER' AS Title, 1 AS RNUM, 400.3 AS VALUE1, null AS DIFF, null AS LAG FROM DUAL UNION ALL
SELECT 'SILVER' AS Title, 2 AS RNUM, 401.3 AS VALUE1, 1.0 AS DIFF, 400.3 AS LAG FROM DUAL UNION ALL
SELECT 'SILVER' AS Title, 3 AS RNUM, 401.3 AS VALUE1, 0 AS DIFF, 401.3 AS LAG FROM DUAL UNION ALL
SELECT 'SILVER' AS Title, 4 AS RNUM, 401.3 AS VALUE1, 0 AS DIFF, 401.3 AS LAG FROM DUAL UNION ALL
SELECT 'SILVER' AS Title, 5 AS RNUM, 402.2 AS VALUE1, 0.9 AS DIFF, 401.3 AS LAG FROM DUAL UNION ALL
SELECT 'SILVER' AS Title, 6 AS RNUM, 403.2 AS VALUE1, 1.0 AS DIFF, 402.2 AS LAG FROM DUAL
)

Using A, I want to get the same result as B.

If the data in the DIFF column is greater than 0 (or according to a condition), I want to fill the value in the AccMaxNo column with the RNUM value in the DIFF column.

    A
Title RNUM VALUE1 DIFF LAG AccMaxNo
GOLD 1 555.4 null null
GOLD 2 555.4 0 555.4
GOLD 3 555.4 0 555.4
GOLD 4 556 0.6 555.4
GOLD 5 556 0 556
GOLD 6 556 0 556
GOLD 7 556.7 0.7 556
GOLD 8 556.7 0 556.7
GOLD 9 557.3 0.6 556.7
SILVER 1 400.3 null null
SILVER 2 401.3 1.0 400.3
SILVER 3 401.3 0 401.3
SILVER 4 401.3 0 401.3
SILVER 5 402.2 0.9 401.3
SILVER 6 403.2 1.0 402.2
QUERY B
Title RNUM VALUE1 DIFF LAG AccMaxNo
GOLD 1 555.4 null null 4
GOLD 2 555.4 0 555.4 4
GOLD 3 555.4 0 555.4 4
GOLD 4 556 0.6 555.4 4
GOLD 5 556 0 556 7
GOLD 6 556 0 556 7
GOLD 7 556.7 0.7 556 7
GOLD 8 556.7 0 556.7 9
GOLD 9 557.3 0.6 556.7 9
SILVER 1 400.3 null null 2
SILVER 2 401.3 1.0 400.3 2
SILVER 3 401.3 0 401.3 5
SILVER 4 401.3 0 401.3 5
SILVER 5 402.2 0.9 401.3 5
SILVER 6 403.2 1.0 402.2 6

CodePudding user response:

You can use the COUNT window function, as in this example:

WITH cnt AS (
  SELECT
    A.*, 
    COUNT(NULLIF(DIFF, 0)) OVER (PARTITION BY TITLE ORDER BY RNUM DESC) AS CNT
  FROM A
)
SELECT 
  TITLE,
  RNUM,
  VALUE1,
  DIFF,
  LAG,
  MAX(RNUM) OVER (PARTITION BY TITLE, CNT) AS AccMaxNo
FROM cnt
ORDER BY TITLE, RNUM

fb<>fiddle

CodePudding user response:

From Oracle 12, you can preform row-by-row processing using MATCH_RECOGNIZE:

SELECT title,
       rnum,
       value1,
       value1 - lag AS diff,
       lag,
       MAX(rnum) OVER (PARTITION BY title, mno) AS accmaxno
FROM   table_name
MATCH_RECOGNIZE(
  PARTITION BY title
  ORDER BY rnum
  MEASURES
    PREV(value1) AS lag,
    MATCH_NUMBER() AS mno
  ALL ROWS PER MATCH
  PATTERN ((^ first_row | same_value)* any_row)
  DEFINE
    same_value AS PREV(value1) = value1
)

Which, for the sample data:

CREATE TABLE table_name (Title, RNUM, VALUE1) AS
SELECT 'GOLD',   1, 555.4 FROM DUAL UNION ALL
SELECT 'GOLD',   2, 555.4 FROM DUAL UNION ALL
SELECT 'GOLD',   3, 555.4 FROM DUAL UNION ALL
SELECT 'GOLD',   4, 556 FROM DUAL UNION ALL
SELECT 'GOLD',   5, 556 FROM DUAL UNION ALL
SELECT 'GOLD',   6, 556 FROM DUAL UNION ALL
SELECT 'GOLD',   7, 556.7 FROM DUAL UNION ALL
SELECT 'GOLD',   8, 556.7 FROM DUAL UNION ALL
SELECT 'GOLD',   9, 557.3 FROM DUAL UNION ALL
SELECT 'SILVER', 1, 400.3 FROM DUAL UNION ALL
SELECT 'SILVER', 2, 401.3 FROM DUAL UNION ALL
SELECT 'SILVER', 3, 401.3 FROM DUAL UNION ALL
SELECT 'SILVER', 4, 401.3 FROM DUAL UNION ALL
SELECT 'SILVER', 5, 402.2 FROM DUAL UNION ALL
SELECT 'SILVER', 6, 403.2 FROM DUAL;

Outputs:

TITLE RNUM VALUE1 DIFF LAG ACCMAXNO
GOLD 1 555.4 null null 4
GOLD 2 555.4 0 555.4 4
GOLD 3 555.4 0 555.4 4
GOLD 4 556 .6 555.4 4
GOLD 5 556 0 556 7
GOLD 6 556 0 556 7
GOLD 7 556.7 .7 556 7
GOLD 8 556.7 0 556.7 9
GOLD 9 557.3 .6 556.7 9
SILVER 1 400.3 null null 2
SILVER 2 401.3 1 400.3 2
SILVER 3 401.3 0 401.3 5
SILVER 4 401.3 0 401.3 5
SILVER 5 402.2 .9 401.3 5
SILVER 6 403.2 1 402.2 6

fiddle

  • Related