sql >> Database >  >> RDS >> Oracle

SQL-query voor het tellen van wijzigingen van waarden in een kolom

Vanaf Oracle 12 kunt u MATCH_RECOGNIZE . gebruiken :

SELECT cat,
       month,
       COUNT(*)
FROM   (
  SELECT t.*,
         TRUNC( "DATE", 'MM' ) AS month
  FROM   table_name t
)
MATCH_RECOGNIZE(
  PARTITION BY cat, month
  ORDER BY "DATE", version
  ONE ROW PER MATCH
  AFTER MATCH SKIP TO LAST change_code
  PATTERN ( strt change_code )
  DEFINE
    change_code AS change_code.some_code <> strt.some_code
)
GROUP BY cat, month

Wat, voor de voorbeeldgegevens:

CREATE TABLE table_name ( CAT, NR, "DATE", VERSION, SOME_CODE ) AS
SELECT 'ABC',   123,    TIMESTAMP '2009-02-19 00:00:00 UTC',    1,  'OPP' FROM DUAL UNION ALL
SELECT 'ABC',   456,    TIMESTAMP '2009-03-18 00:00:00 UTC',    1,  'ZUM' FROM DUAL UNION ALL
SELECT 'ABC',   444,    TIMESTAMP '2009-03-18 00:00:00 UTC',    1,  'ZUM' FROM DUAL UNION ALL
SELECT 'ABC',   444,    TIMESTAMP '2009-03-18 00:00:00 UTC',    2,  'MUZ' FROM DUAL UNION ALL
SELECT 'ABC',   456,    TIMESTAMP '2009-04-18 00:00:00 UTC',    2,  'XXX' FROM DUAL UNION ALL
SELECT 'ABC',   456,    TIMESTAMP '2009-04-18 00:00:00 UTC',    3,  'XXX' FROM DUAL UNION ALL
SELECT 'ABC',   456,    TIMESTAMP '2009-04-18 00:00:00 UTC',    4,  'UIO' FROM DUAL UNION ALL
SELECT 'ABC',   456,    TIMESTAMP '2009-05-18 00:00:00 UTC',    5,  'RQA' FROM DUAL UNION ALL
SELECT 'DEF',   637,    TIMESTAMP '2018-02-16 00:00:00 UTC',    1,  'FAW' FROM DUAL UNION ALL
SELECT 'DEF',   789,    TIMESTAMP '2018-02-17 00:00:00 UTC',    1,  'WER' FROM DUAL UNION ALL
SELECT 'GHI',   248,    TIMESTAMP '2018-02-17 00:00:00 UTC',    1,  'QWE' FROM DUAL UNION ALL
SELECT 'GHI',   248,    TIMESTAMP '2019-02-17 00:00:00 UTC',    2,  'PPP' FROM DUAL UNION ALL
SELECT 'GHI',   357,    TIMESTAMP '2020-02-16 00:00:00 UTC',    1,  'FFF' FROM DUAL UNION ALL
SELECT 'GHI',   420,    TIMESTAMP '2020-02-16 00:00:00 UTC',    1,  'QDS' FROM DUAL UNION ALL
SELECT 'GHI',   357,    TIMESTAMP '2020-02-16 00:00:00 UTC',    2,  'GGG' FROM DUAL UNION ALL
SELECT 'GHI',   357,    TIMESTAMP '2020-02-16 00:00:00 UTC',    3,  'LLL' FROM DUAL UNION ALL
SELECT 'GHI',   357,    TIMESTAMP '2020-02-16 00:00:00 UTC',    4,  'LLL' FROM DUAL UNION ALL
SELECT 'GHI',   357,    TIMESTAMP '2020-08-16 00:00:00 UTC',    4,  'FFF' FROM DUAL UNION ALL
SELECT 'GHI',   357,    TIMESTAMP '2020-10-16 00:00:00 UTC',    5,  'ZZZ' FROM DUAL

Uitgangen:

Als u de wijzigingen wilt zien, kunt u het volgende gebruiken:

SELECT *
FROM   (
  SELECT t.*,
         TRUNC( "DATE", 'MM' ) AS month
  FROM   table_name t
)
MATCH_RECOGNIZE(
  PARTITION BY cat, month
  ORDER BY "DATE", version
  MEASURES
    MATCH_NUMBER()     AS mn,
    FIRST( some_code ) AS change_from,
    LAST( some_code )  AS change_to
  ONE ROW PER MATCH
  AFTER MATCH SKIP TO LAST change_code
  PATTERN ( strt change_code )
  DEFINE
    change_code AS change_code.some_code <> strt.some_code
)

Welke uitgangen:

db<>fiddle hier

Als uw vereiste voor "binnen een maand" is dat u wijzigingen wilt waarbij er maximaal een maand verschil is tussen de vorige rij en de gewijzigde rij, zelfs als de rijen zich in twee verschillende kalendermaanden bevinden (in plaats van alleen de wijzigingen die in dezelfde kalendermaand) dan kunt u het volgende gebruiken:

SELECT cat,
       TRUNC( change_date, 'MM' ) AS month,
       COUNT(*)
FROM   table_name
MATCH_RECOGNIZE(
  PARTITION BY cat
  ORDER BY "DATE", version
  MEASURES
    LAST( "DATE" ) AS change_date
  ONE ROW PER MATCH
  AFTER MATCH SKIP TO LAST change_code
  PATTERN ( strt change_code )
  DEFINE
    change_code AS (
      change_code.some_code <> strt.some_code
      AND MONTHS_BETWEEN( change_code."DATE", strt."DATE" ) <= 1
    )
)
GROUP BY cat, TRUNC( change_date, 'MM' )

Welke uitgangen:

db<>fiddle hier



  1. other_user_id parameter werkt niet op uitvoeringstijd, ik weet niet waarom

  2. Waarom moet ik dubbel escapen (gebruik 4 \) om een ​​backslash ( \ ) te vinden in pure SQL?

  3. SQL Server:RowVersion-equivalent in Oracle

  4. Kolom in MySQL wijzigen van int naar dubbel?