根据版本减少数据
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
我有复杂的逻辑,我正在努力编写它,我不确定我是否可以在单个查询中编写它,或者我需要编写一个函数。我不想逐条循环记录来实现,因为它会影响性能。
要求:我需要根据每个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