Как создать новую запись для перекрывающегося периода между несколькими записями в SQL - PullRequest
0 голосов
/ 27 апреля 2020

Моя проблема очень похожа на:

Как создать новую запись для перекрывающегося периода между двумя записями, используя Informatica / SQL

За исключением случаев, когда я хочу объединить строки, которые я не могу сделать с помощью функции STRING_AGG (), так как я нахожусь на SQL 2016.

Источник:

Tx  ID          FromDate        ToDate
a | 1052260 |   2017-09-15 |    2099-01-01 
b | 1052260 |   2018-09-21 |    2099-01-01 
c | 1052260 |   2018-09-25 |    2099-01-01 
d | 1052260 |   2019-04-01 |    2019-07-31

Ожидаемый результат:

Tx        ID           FromDate        ToDate
a       | 1052260  |   2017-09-15   |  2018-09-21 
a,b     | 1052260  |   2018-09-21   |  2018-09-25 
a,b,c   | 1052260  |   2018-09-25   |  2019-04-01 
a,b,c,d | 1052260  |   2019-04-01   |  2019-07-31 
a,b,c   | 1052260  |   2019-07-31   |  2099-01-01

Ответы [ 2 ]

0 голосов
/ 28 апреля 2020

Приведенный выше ответ действительно помог, но моя ситуация была немного другой, я думаю, поскольку в таблице больше идентификаторов, а значение 'tx' действительно может быть любым строковым значением. В приведенном ниже примере представлено следующее:

Источник

Tx  ID          FromDate        ToDate
a | 1052260 |   2017-09-15 |    2099-01-01 
e | 1052260 |   2018-09-21 |    2099-01-01 
c | 1052260 |   2018-09-25 |    2099-01-01 
d | 1052260 |   2019-04-01 |    2019-07-31
e | 1051582 |   2017-09-15 |    2099-01-01 
b | 1051582 |   2019-04-01 |    2019-07-31

Результат

Tx       ID              FromDate         ToDate
e      | 1051582      |  2017-09-15   |  2019-04-01
e,b    | 1051582      |  2019-04-01   |  2019-07-31
e      | 1051582      |  2019-07-31   |  2099-01-01

a      | 1052260      |  2017-09-15   |  2018-09-21
a,e    | 1052260      |  2018-09-21   |  2018-09-25
a,e,c  | 1052260      |  2018-09-25   |  2019-04-01
a,e,c,d| 1052260      |  2019-04-01   |  2019-07-31
a,e,c  | 1052260      |  2019-07-31   |  2099-01-01
-- Sample Data
DECLARE @table TABLE 
(
  Tx       VARCHAR(3),
  ID       INT,
  FromDate DATE,
  ToDate   DATE
);
INSERT @table (Tx,ID,FromDate,ToDate)
VALUES
('a',1052260,'2017-09-15','2099-01-01'),
('e',1052260,'2018-09-21','2099-01-01'),
('c',1052260,'2018-09-25','2099-01-01'),
('d',1052260,'2019-04-01','2019-07-31'),
('e',1051582,'2017-09-15','2099-01-01'),
('b',1051582,'2019-04-01','2019-07-31');

-- Solution
WITH x AS(
  SELECT
    t.Tx,
    t.ID,
    t.FromDate,
    ToDate = LEAD(t.FromDate,1,t.ToDate) OVER (partition by t.Id ORDER BY t.FromDate)
  FROM        @table AS t
  CROSS APPLY 
  (
    SELECT   ','+t2.Tx
    FROM     @table AS t2
    WHERE    --t2.Tx <= t.Tx and 
    t2.ID = t.ID
    ORDER BY t.Tx FOR XML PATH('')
  ) AS stringAgg(Txt)
)
,xx AS(
  SELECT  max(x.Tx) as Tx, x.ID, max(x.FromDate) as Fromdate, max(x.ToDate) as ToDate
  FROM   x 
  group by x.ID
 -- ORDER BY  x.ID DESC

)
SELECT
  tx = CONCAT((
  SELECT x2.Tx+',' 
  FROM x AS x2 
  WHERE x2.ToDate < x.ToDate and 
  x2.ID = x.ID
  ORDER BY x.Tx FOR XML PATH('')),x.Tx),
  x.ID, x.FromDate, x.ToDate
FROM x
UNION ALL
SELECT 
  STUFF((
  SELECT ','+x2.Tx 
  FROM x AS x2 
  WHERE x2.ToDate < xx.ToDate 
  and x2.ID = xx.ID
  ORDER BY xx.Tx FOR XML PATH('')),1,1,''), 
  xx.ID, xx.ToDate, '2099-01-01'
FROM xx
order by ID,  FromDate;
0 голосов
/ 28 апреля 2020
-- Sample Data
DECLARE @table TABLE 
(
  Tx       VARCHAR(3),
  ID       INT,
  FromDate DATE,
  ToDate   DATE
);
INSERT @table (Tx,ID,FromDate,ToDate)
VALUES
('a',1052260,'2017-09-15','2099-01-01'),
('b',1052260,'2018-09-21','2099-01-01'),
('c',1052260,'2018-09-25','2099-01-01'),
('d',1052260,'2019-04-01','2019-07-31');

-- Solution
WITH x AS
(
  SELECT
    t.Tx,
    t.ID,
    t.FromDate,
    ToDate = LEAD(t.FromDate,1,t.ToDate) OVER (ORDER BY t.Tx)
  FROM        @table AS t
  CROSS APPLY 
  (
    SELECT   ','+t2.Tx
    FROM     @table AS t2
    WHERE    t2.Tx <= t.Tx
    ORDER BY t.Tx FOR XML PATH('')
  ) AS stringAgg(Txt)
),
xx AS
(
  SELECT TOP(1) x.Tx, x.ID, x.FromDate, x.ToDate
  FROM   x 
  ORDER BY x.Tx DESC
)
SELECT
  tx = CONCAT((SELECT x2.Tx+',' FROM x AS x2 WHERE x2.Tx < x.Tx ORDER BY x.Tx FOR XML PATH('')),x.Tx),
  x.ID, x.FromDate, x.ToDate
FROM x
UNION ALL
SELECT 
  STUFF((SELECT ','+x2.Tx FROM x AS x2 WHERE x2.Tx < xx.Tx ORDER BY xx.Tx FOR XML PATH('')),1,1,''), 
  xx.ID, xx.ToDate, '2099-01-01'
FROM xx;

Результаты:

tx            ID          FromDate   ToDate
------------- ----------- ---------- ----------
a             1052260     2017-09-15 2018-09-21
a,b           1052260     2018-09-21 2018-09-25
a,b,c         1052260     2018-09-25 2019-04-01
a,b,c,d       1052260     2019-04-01 2019-07-31
a,b,c         1052260     2019-07-31 2099-01-01
...