根据版本减少数据

Reduce the data based on version

我有复杂的逻辑,我正在努力编写它,我不确定我是否可以在单个查询中编写它,或者我需要编写一个函数。我不想逐条循环记录来实现,因为它会影响性能。

要求:我需要根据每个ID的版本减少源table并调整日期。检查版本 1 然后将其输出,检查版本 2 如果 AT1 != AT2 然后将其输出但使以前的版本不活动并调整版本 1 的日期。

来源Table:

输出:

SQL 我试过了,但我无法继续下去,因为合并所有逻辑很复杂。能不能指导一下。

 with history as (SELECT ID,VERSION,FROM ,TO,AT1,AT2 FROM hrhistory),
      prev as (SELECT *, lead(FROM) over(partition by ID order by version ) new_fromm
                       ,lead(To) over (partition by ID order by version ) new_to
                        FROM hrhistory
               where at1!=at2)
               
               select * from prev
     SELECT a.*
     FROM history a LEFT OUTER JOIN prev b
     ON a.ID=b.ID
     WHERE b.ID IS NULL

从 Oracle 12 开始,您可以使用:

SELECT id,
       "FROM",
       COALESCE( LEAST( next_from, "TO" ), "TO" ) AS "TO",
       at1,
       at2,
       NVL2( next_from, 'inactive', 'active' ) AS active
FROM   (
  SELECT t.*,
         LEAD( "FROM" ) OVER ( PARTITION BY id ORDER BY mn) AS next_from
  FROM   table_name
  MATCH_RECOGNIZE (
    PARTITION BY id
    ORDER     BY "FROM", "TO"
    MEASURES
      MATCH_NUMBER() AS mn,
      FIRST( same_at."FROM" ) AS "FROM",
      MAX( same_at."TO" ) AS "TO",
      FIRST( at1 ) AS at1,
      FIRST( at2 ) AS at2
    ONE ROW PER MATCH
    PATTERN ( same_at+ )
    DEFINE same_at AS (
          FIRST(at1) = at1
      AND FIRST(at2) = at2
    )
  ) t
)

在此之前,您可以使用:

SELECT id,
       MIN( "FROM" ) AS "FROM",
       COALESCE(
         LEAST(
           MAX( next_from ) KEEP ( DENSE_RANK LAST ORDER BY "FROM", "TO" ),
           MAX( "TO" )
         ),
         MAX( "TO" )
       ) AS "TO",
       MIN( at1 ) AS at1,
       MIN( at2 ) AS at2,
       NVL2(
         MAX( next_from ) KEEP ( DENSE_RANK LAST ORDER BY "FROM", "TO" ),
         'inactive',
         'active'
       ) AS active
FROM   (
  SELECT t.*,
         SUM( has_changed_group ) OVER ( PARTITION BY id ORDER BY "FROM", "TO" )
           AS grp
  FROM   (
    SELECT t.*,
           CASE
           WHEN at1 = LAG( at1 ) OVER ( PARTITION BY id ORDER BY "FROM", "TO" )
           AND  at2 = LAG( at2 ) OVER ( PARTITION BY id ORDER BY "FROM", "TO" )
           THEN 0
           ELSE 1
           END AS has_changed_group,
           LEAD( "FROM" ) OVER ( PARTITION BY id ORDER BY "FROM", "TO" )
             AS next_from
    FROM   table_name t
  ) t
)
GROUP BY id, grp

其中,对于示例数据:

CREATE TABLE table_name ( id, version, "FROM", "TO", at1, at2 ) AS
SELECT 1, 1, DATE '2020-01-01', DATE '2020-01-05', 'L1', 'L1' FROM DUAL UNION ALL
SELECT 1, 2, DATE '2020-01-03', DATE '2020-01-10', 'L1', 'L2' FROM DUAL UNION ALL
SELECT 1, 3, DATE '2020-01-05', DATE '2020-01-15', 'L1', 'L2' FROM DUAL UNION ALL
SELECT 1, 3, DATE '2020-01-10', DATE '2020-01-20', 'L1', 'L1' FROM DUAL UNION ALL
SELECT 2, 1, DATE '2020-01-01', DATE '2020-01-10', 'L1', 'L3' FROM DUAL;

然后两个查询输出:

ID | FROM                | TO                  | AT1 | AT2 | ACTIVE  
-: | :------------------ | :------------------ | :-- | :-- | :-------
 1 | 2020-01-01 00:00:00 | 2020-01-03 00:00:00 | L1  | L1  | inactive
 1 | 2020-01-03 00:00:00 | 2020-01-10 00:00:00 | L1  | L2  | inactive
 1 | 2020-01-10 00:00:00 | 2020-01-20 00:00:00 | L1  | L1  | active  
 2 | 2020-01-01 00:00:00 | 2020-01-10 00:00:00 | L1  | L3  | active  

db<>fiddle here