SQL Server 2012 折叠成最小行数失败

SQL Server 2012 Collapsing into minimum rows failing

我正在尝试创建一个时间序列来跟踪证券更改审计中金融证券随时间的变化 table AdvApp.vSecurity_Hist h。我只想查看具有唯一安全标识符(Symbol、ISIN、SEDOL、CUSIP)的最小日期的行。我只想查看其中任何一个发生更改的行。这些更改是由于公司重组引起的,但系统生成的 SecurityID 没有更改。我只希望每个不同的安全 ID 在其他列中进行更改这是合法更改 3 次的安全示例及其更改日期。这里查询结果没有问题

有变化的合法时间序列。

请注意,如果同一天有多个更改,那么具有最长时间的行将被选中。我正在寻找每日变化,而不是日内变化。

SecurityID  MinDate CUSIP   ISIN    SEDOL   Symbol  SecurityCount
5156    2011-10-22  61745P635           iqc 3
5156    2012-01-31  46130M107           iqc 3
5156    2012-09-12  46130m107           iqcoldx 3

这里是一个有问题的时间序列的原始数据的例子,它打破了我的查询。注意第 10 行在 CUSIP 字段中缺少一个值,有时没有 CUSIP 是合法的,但规则是如果相同的 CUSIP 值在空白字段之前和之后,那么空白字段是不合法的,应该用该字段中的前后值。如您所见,CUSIP 值在第 11 行恢复。

问题集来自原始数据

SecurityID  CUSIP   ISIN    SEDOL   Symbol  OptionSymbol    AuditEventTime
5060    233809201           fduxx       2011-10-22 00:12:31.310
5060    233809201           fduxx       2012-03-21 19:33:41.387
5060    233809201           fduxx       2012-03-21 21:40:05.813
5060    233809201           fduxx       2012-03-30 15:00:45.243
5060    233809201           fduxx       2012-04-04 11:31:59.280
5060    233809201           fduxx       2012-05-15 09:19:38.360
5060    233809201           fduxx       2012-05-15 10:04:10.597
5060    233809201           fduxx       2012-07-03 15:54:41.043
5060    233809201           fduxx       2013-04-04 18:25:27.253
5060                fduxx       2013-09-26 09:45:00.137
5060    233809201           fduxx       2013-10-01 13:03:59.277
5060    233809201           fduxx       2016-12-02 18:52:53.093
5060    233809201           fduxx       2017-10-06 08:43:58.717

这是我根据这个有问题的数据查询的结果。该查询希望在更改的最小日期进行分组,因此它选择第 1 行和第 9 行,但随后忽略导致一些问题的第 11-13 行。

查询结果。

根据我的规则,我不希望第二行有空白的 CUSIP 字段,因为它之前和之后的行在所有字段中都有匹配值。

SecurityID  MinDate CUSIP   ISIN    SEDOL   Symbol  SecurityCount
5060    2011-10-22  233809201           fduxx   2
5060    2013-09-26              fduxx   2

我正在考虑利用使用超前和滞后的逻辑,如果有空白行但超前值和滞后值彼此匹配(不包括时间),则将超前 CUSIP 值放在空白行中。这样我就可以将 SecurityID 为 5060 的数据集折叠成一行。我认为要做到这一点,我需要更改我的分区或我的查询,以便它识别最后的第 11-13 行实际上是第三个系列。现在,最后几行被忽略了,因为这些值与空白之前的数据相匹配,因此不是该集合的最小日期。这是我的 SQL 查询。我想知道以下内容:

1)How can I make the query result produce three rows for SecurityID 5060? (Make it consider the data that comes after the blank as it's own row)
2)where and how in the query should I then apply Lead and Lag to help fill in the blank and then collapse the result into a single row?

谢谢

我当前的查询

WITH DATA AS
(
SELECT 
b.SecurityID,
MIN(b.AuditEventDate)MinDate,
b.CUSIP,
b.ISIN,
b.SEDOL,
b.Symbol,
COUNT(b.SecurityID) OVER (PARTITION BY b.SecurityID)SecurityCount
FROM
(
SELECT a.*,
MAX(a.AuditEventTime) OVER (PARTITION BY a.SecurityID,a.AuditEventDate) MaxTime
FROM
(
SELECT distinct
h.SecurityID
,h.AuditEventTime
,CAST(h.AuditEventTime AS DATE)AuditEventDate
,CASE WHEN ISNULL(h.OptionSymbol,'') <> '' THEN h.OptionSymbol ELSE h.Symbol END Symbol
,h.CUSIP
,h.SEDOL
,h.ISIN
FROM APXFirm.AdvApp.vSecurity_Hist h
WHERE 1 = 1
AND (LEN(h.CUSIP) = 9 OR ISNULL(h.CUSIP,'') = '')
AND (LEN(h.SEDOL) = 7 OR ISNULL(h.SEDOL,'') = '') 
AND (LEN(h.ISIN) = 12 OR ISNULL(h.ISIN,'') = '') 
AND h.SecurityID = 5060
)a
)b
WHERE b.AuditEventTime = b.MaxTime
GROUP BY b.SecurityID,
         b.CUSIP,
         b.ISIN,
         b.SEDOL,
         b.Symbol
)
SELECT * FROM Data 
WHERE DATA.SecurityCount > 1
ORDER BY Data.SecurityID,MINDate

您将需要 "fix" 源中的 NULL 值(尽早),否则您在分组后没有可靠的 "previous/following" 可用行关系,例如

  SELECT
        b.SecurityID
      , MIN(b.AuditEventDate)                                mindate
      , b.CUSIP
      , b.ISIN
      , b.SEDOL
      , b.Symbol
      , COUNT(b.SecurityID) OVER (PARTITION BY b.SecurityID) securitycount
  FROM (
        SELECT
              a.*
            , MAX(a.AuditEventTime) OVER (PARTITION BY a.SecurityID, a.AuditEventDate) maxtime
        FROM (
              SELECT DISTINCT /* but I doubt that distinct does anything useful */
                    h.SecurityID
                  , h.AuditEventTime
                  , CAST(h.AuditEventTime AS date)                                                   auditeventdate
                  , CASE WHEN ISNULL(h.OptionSymbol, '') <> '' THEN h.OptionSymbol ELSE h.Symbol END symbol
                  , case when h.CUSIP IS NULL and  lag(h.CUSIP,1) over(order by AuditEventTime)
                                               =  lead(h.CUSIP,1) over(order by AuditEventTime)
                         then lead(h.CUSIP,1) over(order by AuditEventTime)
                         else h.CUSIP
                    end as CUSIP
                  , h.SEDOL
                  , h.ISIN
              FROM vSecurity_Hist h
              /* where clause needed here */
        ) a
  ) b
  WHERE b.AuditEventTime = b.MaxTime
  GROUP BY
        b.SecurityID
      , b.CUSIP
      , b.ISIN
      , b.SEDOL
      , b.Symbol

Demo