审计表上的SQL Server CTE以获取最新记录

时间:2011-10-25 16:32:04

标签: sql tsql common-table-expression

好的,这是一个头部清障车,我会尽量保持简短。

我有两个表,Security和SecurityAudit 只有在进行更改时,Audit表才会保留对Security表的任何更改的副本。 SecurityId是Foriegn键。因此,最近的记录总是在安全表中,如果有更改,则将其写入Audit表,并将ValidToDate设置为记录有效的日期

[Security](
    [SecurityID] [bigint] IDENTITY(10000,1) NOT NULL,
    [Security] [nvarchar](255) NOT NULL,
    [ISIN] [nvarchar](20) NOT NULL,
    [CountryOfIncID] [bigint] NOT NULL,
    [SecurityTypeID] [bigint] NOT NULL,
    [SubTypeID] [bigint] NOT NULL,
    [ISQ] [bigint] NOT NULL,
    [MemberStateID] [bigint] NULL,
    [ManualOverride] [bit] NULL,

这是审核表

[SecurityAudit](
          [SecurityAuditID] [bigint] IDENTITY(10000,1) NOT NULL,
          [SecurityID] [bigint] NOT NULL,
          [Security] [nvarchar](255) NOT NULL,
          [CountryOfIncID] [bigint] NOT NULL,
          [SubTypeID] [bigint] NOT NULL,
          [ISQ] [bigint] NOT NULL,
          [MemberStateID] [bigint] NULL,
          [ValidToDateID] [datetime] Not NULL

所以我的问题是我现在想要获得在特定时间点发挥作用的所有证券。这意味着从安全表中获取所有从未进行过更改的证券,然后从审计表中获取该时间点的相关安全性。

我以为我会用CTE,联盟和Rank来做到这一点,但是我已经撞墙了。到目前为止它看起来像这样......

With
    cteAllSecurities (RowNum,SecurityID, Security, ISQ, CountryOfIncorporationID, ValidToDate)
    AS
    (
        SELECT RowNum=row_number() OVER (Partition By Security order by ValidToDate desc),
            sa.SecurityID, sa.Security, sa.ISQ, sa.CountryOfIncorporationID, CONVERT(varchar(30), sa.ValidToDate,106)
          FROM
            SecurityAudit sa 
        UNION 
        SELECT 0 as RowNum,
            s.SecurityID, s.Security, s.ISQ, s.CountryOfIncorporationID, CONVERT(varchar(30), GetUtcDate(),106) as ValidToDate
          FROM 
            Security s
    )
    SELECT RowNum, SecurityID, Security, ISQ, CountryOfIncorporationID, ValidToDate
    FROM cteAllSecurities
    order by securityid
    Where row_number() = 1

所以我联合了Securites表,它具有审计的最后一个并给他们一个行号。我当时希望获得行号为0且没有子记录的所有证券...即审计表中的子计数为0且审计记录小于我正在寻找的日期并采取最重要的一个。

所以我到目前为止。我是在正确的轨道上,烹饪它,还是只是疯狂计划。任何帮助将不胜感激。

问候M

2 个答案:

答案 0 :(得分:1)

认为您应该能够通过以下查询获得您正在寻找的结果:

AllSecurity (Security, ISQ, CountryOfIncorporationID, ValidToDate)
AS (
    SELECT Security, ISQ, CountryOfIncID, CONVERT(DATETIME, '9999-12-31 23:59:59.997')
    FROM Security
        UNION
    SELECT Security, ISQ, CountryOfIncID, ValidToDate
    FROM SecurityAudit
)
SELECT TOP 1 Security, ISQ, CountryOfIncorporationID, ValidToDate
FROM AllSecurity A
WHERE ValidToDate = (
    SELECT MIN(ValidToDate)
    FROM AllSecurity B
    WHERE B.Security = A.Security
      AND ValidToDate > @SearchDate
)

您显然希望将@SearchDate替换为您正在寻找的值。

此查询将联合“当前”安全表,将ValidToDate设置为SQL Server接受的最大DATETIME值,并将其与审计表联合。然后,使用子查询,我们得到的“最接近”(最小)ValidToDate大于我们正在查看的日期。

答案 1 :(得分:0)

好的,这就是我约会的日期...... Galador ......我会看看你的朋友,因为它看起来更好......我唯一关心的是这是多么高效...我不希望安全表在一年内超过30,000条记录,并且有大约300,000条审计

With
    cteAllSecurities (RowNum,SecurityID, Security, ISQ, CountryOfIncorporationID, ValidToDate)
    AS
    (   -- Get all the securites and union the with the History records that we are interested in
        SELECT RowNum=row_number() OVER (Partition By Security order by ValidToDate desc),
            sa.SecurityID, sa.Security, sa.ISQ, sa.CountryOfIncID, CONVERT(varchar(30), sa.ValidToDate,106)
          FROM
            SecurityAudit sa 
          WHERE
            ValidToDate >= Cast('08-22-2011' as datetime)  -- filter out the records that we dont need
        UNION 
        SELECT 0 as RowNum,  -- make this Row num 0 so we can group on them
            s.SecurityID, s.Security, s.ISQ, s.CountryOfIncID, CONVERT(varchar(30), GetUtcDate(),106) as ValidToDate
          FROM 
            Security s
    ),
    cteMaxSecurties ( SecurityID, MaxValidToDate)
    AS
    (
        -- now get all the securities and find out their max date... 
        select SecurityID, Max(ValidToDate) from
            cteAllSecurities
          Group by SecurityID

    )   -- now join the max date and security
    SELECT RowNum, cteAllSecurities.SecurityID, Security, ISQ, CountryOfIncID, ValidToDate
    FROM cteAllSecurities Left Join cteMaxSecurties
            on cteAllSecurities.SecurityID = cteMaxSecurties.SecurityID and cteAllSecurities.ValidToDate = cteMaxSecurties.MaxValidToDate
    order by Security