sql >> Databáze >  >> RDS >> Oracle

SQL dotaz pro počítání změn hodnot ve sloupci

Od Oracle 12 můžete použít 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

Což pro ukázková data:

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

Výstupy:

Pokud chcete vidět změny, můžete použít:

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
)

Které výstupy:

db<>fiddle zde

Pokud je vaším požadavkem „do jednoho měsíce“ to, že chcete změny tam, kde je mezi předchozím řádkem a změněným řádkem rozdíl nejvýše jednoho měsíce, i když jsou řádky ve dvou různých kalendářních měsících (spíše než jen změny, ke kterým dojde ve stejném kalendářním měsíci), pak můžete použít:

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' )

Které výstupy:

db<>fiddle zde



  1. Nepodařilo se najít funkci převodu z neznámého na text

  2. Příznaky MySQL ve výpisech

  3. OracleSQL převádí pole Datum do jiného časového pásma

  4. Má mysql nějaké omezení na počet databází