SQL: что-то вроде пересечения ... проблема с древовидной навигацией по историческим данным - PullRequest
0 голосов
/ 20 марта 2019

Есть ли способ получить дополнение к пересечению двух записей в SQL?

Например, у меня есть две записи:

KEY BEG_DATE END_DATE FATHER DEEP
K1  1 jan    30 jun   F1      0
K1  1 jan    31 dec   F2      1

Я бы хотел получить

KEY BEG_DATE END_DATE FATHER DEEP
K1  1 jan    30 jun   F1      0
K1  1 jul    31 dec   F2      1

Реальная ситуация такова, что у меня есть организационные подразделения, которые должны относиться к отцу организационных подразделений и могут относиться к центру затрат. Если нет явной связи с МВЗ, текущая организационная единица наследует МВЗ от отца (или его предков ...)

С очень запутанным утверждением я получил результат, но мой SQL не работает в том случае, если у меня есть явное отношение с Cost Center, которое закрыто ДО конца его ссылочной единицы org, и я не могу перейти на один (или более) шаги выше

Просто попробовать SqlFiddle

DDL

CREATE TABLE Org (
  IDOrg char(6),
  Beg_O DATE,
  End_O DATE);

CREATE TABLE Org_REL (
  IDOrg char(6),
  IDOrgFather char(6),
  Beg_OO date,
  End_OO date);

CREATE TABLE Org_Cost (
  IDOrg char(6),
  IDCostCenter char(10),
  Beg_OC date,
  End_OC date);

ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';

INSERT INTO Org
  SELECT 'Org0', '2018-01-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Org1', '2018-01-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Org2', '2018-01-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Org3', '2018-01-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Orgx1', '2018-01-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Orgx2', '2018-01-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Orgx3', '2018-01-01', '9999-12-31' FROM DUAL ;

INSERT INTO Org_REL 
  SELECT 'Org1', 'Org0', '2018-01-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Org2', 'Org0', '2018-01-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Org3', 'Org1','2018-01-01', '2018-06-30' FROM DUAL UNION
  SELECT 'Org3', 'Org2','2018-07-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Orgx1', 'Org3','2018-01-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Orgx2', 'Org3','2018-01-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Orgx3', 'Org1','2018-01-01', '9999-12-31' FROM DUAL;

INSERT INTO Org_Cost 
  SELECT 'Org0', 'Cost0', '2018-01-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Org1', 'Cost1', '2018-01-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Org2', 'Cost2', '2018-01-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Orgx1', 'Cost_x1', '2018-01-01', '9999-12-31' FROM DUAL UNION
  SELECT 'Orgx3', 'Cost_x3', '2018-01-01', '2018-07-31' FROM DUAL ;

DML

select
    CONNECT_BY_ROOT Org.IDOrg LEAF,
    Org_REL.IDOrg,
    Org_REL.IDOrgFather,
    Org_REL.Beg_OO Beg_OO,
    Org_REL.End_OO End_OO,
    level DEEP,
    SYS_CONNECT_BY_PATH(Org_REL.IDOrg, '*') path
from 
    Org
    LEFT OUTER JOIN Org_REL on Org.IDOrg = ORG_Rel.IDOrg
WHERE 1=1
CONNECT BY --NOCYCLE 
  PRIOR Org_REL.IDOrgFather = Org_REL.IDOrg
UNION
SELECT
    IDOrg, null, IDOrg, BEG_O, END_O, 0, '*' || IDOrg
FROM Org
)
, 

final as (
select 
  LEAF, PATH, DEEP, IdOrgFather, IDCostCenter, 
  TO_CHAR(CASE 
    WHEN t.Beg_OO < oc.Beg_OC THEN oc.Beg_OC 
    ELSE t.Beg_OO
  END, 'YYYY-MM') BEGVAL, 
  TO_CHAR(CASE 
    WHEN t.End_OO > oc.End_OC THEN oc.End_OC 
    ELSE t.End_OO
  END, 'YYYY-MM') ENDVAL
  , RANK() OVER (PARTITION BY LEAF ORDER BY DEEP) ORD
from 
  tree t left outer join
  Org_Cost oc on t.IDOrgFather = oc.IDOrg
WHERE
    IDCostCenter is not null
)
--SELECT * FROM FINAL WHERE leaf = 'Orgx3'

select
LEAF, IDCostCenter, BEGVAL, ENDVAL, ORD
from final 
WHERE 
  LEAF IN ('Orgx1', 'Orgx2', 'Orgx3') 
  AND ORD = 1

я получаю следующие записи

|   LEAF | IDCOSTCENTER |  BEGVAL |  ENDVAL | ORD |
|--------|--------------|---------|---------|-----|
| Orgx1  |   Cost_x1    | 2018-01 | 9999-12 |   1 |
| Orgx2  |   Cost1      | 2018-01 | 2018-06 |   1 |
| Orgx2  |   Cost2      | 2018-07 | 9999-12 |   1 |
| Orgx3  |   Cost_x3    | 2018-01 | 2018-07 |   1 |

из которых

  • первый в порядке (явные отношения)
  • второе и третье в порядке (нет явного отношения, наследуют для иерархии)
  • четвертое частично верно, потому что я хотел бы также наследственное отношение после '2018-07

если я удалю предложение AND ORD = 1, которое я получу (только для orgx3)

|   LEAF | IDCOSTCENTER |  BEGVAL |  ENDVAL | ORD |
|--------|--------------|---------|---------|-----|
| Orgx3  |   Cost_x3    | 2018-01 | 2018-07 |   1 |
| Orgx3  |   Cost1      | 2018-01 | 9999-12 |   2 |
| Orgx3  |   Cost0      | 2018-01 | 9999-12 |   3 |

, где первая запись уже захвачена, но вторая должна начинаться не с 2018-01, а с 2018-08

...