Ab Oracle 12 können Sie MATCH_RECOGNIZE
verwenden :
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
Was für die Beispieldaten:
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
Ausgaben:
Wenn Sie die Änderungen sehen möchten, können Sie Folgendes verwenden:
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
)
Welche Ausgaben:
db<>fiddle hier
Wenn Ihre Anforderung für "innerhalb eines Monats" darin besteht, dass Sie Änderungen wünschen, bei denen zwischen der vorherigen Zeile und der geänderten Zeile höchstens ein Monat Unterschied besteht, selbst wenn sich die Zeilen in zwei verschiedenen Kalendermonaten befinden (und nicht nur die Änderungen, die auftreten im selben Kalendermonat), dann können Sie Folgendes verwenden:
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' )
Welche Ausgaben:
db<>fiddle hier