0

问题

我有一个如下所示的起始表:

起始数据

我正在尝试编写一个 SQL 查询,该查询将把这些数据写入一个类似格式的表中,但带有额外的装饰,表明记录何时过期以及哪些记录处于活动状态。结果将如下所示:

identifier                       | loaddate   | loadenddate | activeflag | symbol
723a90699e99ec9e00216910910384bd | 2020-04-01 | 2020-04-07  | 0          | DXB
723a90699e99ec9e00216910910384bd | 2020-04-08 | 2999-12-31  | 1          | DXB CL

请注意,有 1000 种不同的标识符,其中一些在各种不同的时间范围内具有一个、两个、三个 + 不同的符号。

要求

  1. 任何时候第一次看到标识符时,都必须在最终表中创建它,并将今天的日期作为加载日期,并且加载日期为 2999-12-31,并且 activeflag=1
  2. 在第二天看到该标识符时,仅在符号已更改时才添加一行。如果有,则通过将前一行的 loadenddate 设置为此新行的 loaddate - 1 天和 activeflag = 0 来使前一行“过期”
  3. sql 查询(或多个查询)还需要能够每天在源表上重新运行,以便它们正确处理目标表中的现有数据以及目标表为空白(初始运行)

到目前为止我得到了什么

要最初加载(而不是重复),我有以下 SQL:

INSERT INTO finaltable(
listinghashkey
symbol,
loaddate,
loadenddate,
activeflag
)
SELECT
s.listinghashkey
s.symbol,
MAX(s.loaddate),
'2999-12-31 00:00:00.0',
1
FROM
startingtable s
LEFT JOIN finaltable f ON s.listinghashkey = f.listinghashkey
WHERE (f.listinghashkey IS NULL)
GROUP BY s.listinghashkey, s.symbol
4

1 回答 1

1

将您的初始格式转换为新格式非常容易,因为这是一个孤岛问题:

select identifier, symbol, min(loaddate),
       nullif(max(loaddate), max_loaddate)
from (select s.*,
             max(loaddate) over () as max_loaddate,
             row_number() over (partition by identifier order by loaddate) as seqnum,
             row_number() over (partition by identifier, symbol order by loaddate) as seqnum_2
      from startingtable
     ) s
group by identifier, symbol, (seqnum - seqnum_2);

这避开了“活跃”标志和任意未来日期。它只是NULL用于无限的未来。(您可以轻松调整版本的逻辑;这只是更易于使用。)

如果您有此表并且想要添加下一个加载日期,那么您可以使用union all. 这个想法是将处理分为四个步骤:

  • 已经关闭的历史记录,因此新数据不会影响它们。
  • 新数据与现有数据一致的记录,因此没有任何变化。
  • 不在新数据中的记录,因此需要关闭现有记录。
  • 新纪录。

SQL 看起来像:

-- all completed records
select ft.identifier, ft.symbol, ft.loaddate, ft.loadenddate
from finaltable ft
where loadenddate is not null
union all
-- Basically copy over records where the new data is consistent
select ft.identifer, ft.symbol, ft.loaddate, ft.loadenddate
from finaltable ft join
     oneload ol
     on ft.identifier = ol.identifier and
        ft.symbol = ol.symbol
where ft.loadenddate is null
union all
-- close records that are not in the new batch
select ft.identifer, ft.symbol, ft.loaddate, m.loaddate - interval '1 day'
from finaltable ft cross join
     (select max(loaddate) as loaddate
      from oneload
     ) m left join
     oneload ol
     on ft.identifier = ol.identifier and
        ft.symbol = ol.symbol
where ft.loadenddate is null
-- finally add new records
select ol.identifer, ol.symbol, ol.loaddate, null
from oneload ol left join
     finaltable ft
     on ft.identifier = ol.identifier and
        ft.symbol = ol.symbol and
        ft.loadenddate is null
where ft.identifier is null;

我更喜欢将其作为select/replace 操作而不是一系列insert/update步骤(或merge可能使用)。但你这是基本的想法。

于 2020-12-12T13:45:29.543 回答