SQL Server 2012折叠到最小行失败

时间:2017-12-22 01:10:48

标签: sql sql-server partition

我正在尝试创建一个时间序列,以便从安全更改审核表AdvApp.vSecurity_Hist h跟踪金融证券随时间的变化。我想只看到具有MIN日期的行,用于唯一的安全标识符,即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

我正在考虑使用超前和滞后的逻辑,如果有一个空行,但是led和滞后值相互匹配(不包括时间),那么将前导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

1 个答案:

答案 0 :(得分:1)

您需要在源处“修复”该NULL值(尽可能早),否则您在分组后没有可靠的“上一个/后一个”行关系,例如。

  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