Da Oracle 12, puoi utilizzare MATCH_RECOGNIZE
:
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
Quale, per i dati di esempio:
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
Uscite:
Se vuoi vedere le modifiche, puoi usare:
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
)
Quali uscite:
db<>violino qui
Se il tuo requisito per "entro un mese" è che desideri modifiche in cui c'è al massimo un mese di differenza tra la riga precedente e la riga modificata, anche se le righe si trovano in due mesi di calendario diversi (piuttosto che solo le modifiche che si verificano nello stesso mese solare), quindi puoi utilizzare:
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' )
Quali uscite:
db<>violino qui