SQL Server CTE в таблице аудита для получения последней записи - PullRequest
0 голосов
/ 25 октября 2011

хорошо, это главный вредитель, и я постараюсь быть кратким.

У меня есть две таблицы: Security и SecurityAudit. В таблице Audit хранится копия любых изменений в таблице Security, только если они были внесены.,SecurityId - это внешний ключ.Таким образом, самая последняя запись всегда находится в таблице безопасности, и если есть изменение, то она записывается в таблицу аудита, и 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, а Union иЗвание, но я врезался в стену.Пока это выглядит так ...

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, которая имеет последнюю, с Audit, и даю им номер строки.Затем я надеялся получить все ценные бумаги с номером строки 0 и без дочерних записей ... т. Е. Счетчик детей 0 в таблице аудита и записях аудита, которые меньше даты, которую я ищу, и забратьверхний.

Итак, я так далеко.Я на правильном пути, готовлю это или просто планирую сойти с ума.Любая помощь будет принята с благодарностью.

С уважением, M

Ответы [ 2 ]

1 голос
/ 25 октября 2011

I думаю, вы сможете получить результаты, которые вы ищете, с помощью запроса, такого как:

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 максимальное значение DATETIME, которое принимает SQL Server, и объединит его с таблицей аудита. Затем, используя подзапрос, мы получаем «ближайший» (минимальный) ValidToDate, который больше, чем дата, на которую мы смотрим.

0 голосов
/ 26 октября 2011

Хорошо, вот что я должен встречаться ... Галадор ... я посмотрю на тебя и моего друга, так как он выглядит лучше ... Единственное, что меня беспокоит, так это то, насколько это эффективно ... Я не ожидаю таблица безопасности будет более 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
...