Удалить неизмененные строки между двумя датами - PullRequest
0 голосов
/ 01 февраля 2019

Я унаследовал очень старую и огромную (100M строк) таблицу в SQL Server.Это ежедневный снимок счетов и остатков, но некоторые из этих учетных записей даже больше не меняются, а добавляются каждый день (не спрашивайте почему!)

Я хочу:

  • Идентификация и удаление неизмененных строк, если нет изменений

  • Создайте запрос, который даст мне удаленные строки, когда они этого захотят, как если бы они все еще были там

У меня есть таблица измерений даты, которую можно использовать.

Это создает текущую таблицу:

CREATE TABLE #Account_Snapshot(
[Snapshot_Id] [int] NOT NULL,
[Snapshot_Date] [date] NOT NULL,
[Account] [nvarchar](20) NOT NULL,
[Balance] [decimal](18, 2) NOT NULL,
CONSTRAINT [PK_Account_Snapshot_1] PRIMARY KEY CLUSTERED 
(
    [Snapshot_Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = 
OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

INSERT INTO #Account_Snapshot VALUES(1, '2019-01-01', '1', 1505.31)
INSERT INTO #Account_Snapshot VALUES(2, '2019-01-01', '2', 2337.48)
INSERT INTO #Account_Snapshot VALUES(3, '2019-01-01', '3', 1088.07)

INSERT INTO #Account_Snapshot VALUES(4, '2019-02-01', '1', 1505.31)
INSERT INTO #Account_Snapshot VALUES(5, '2019-02-01', '2', 2132.17)
INSERT INTO #Account_Snapshot VALUES(6, '2019-02-01', '3', 1088.07)

INSERT INTO #Account_Snapshot VALUES(7, '2019-03-01', '1', 1505.31)
INSERT INTO #Account_Snapshot VALUES(8, '2019-03-01', '2', 2132.17)
INSERT INTO #Account_Snapshot VALUES(9, '2019-03-01', '3', 749.23)

SELECT * FROM #Account_Snapshot
ORDER BY  Account, Snapshot_Date


Snapshot_Id Snapshot_Date Account              Balance
----------- ------------- -------------------- ---------------------
1           2019-01-01    1                    1505.31
4           2019-02-01    1                    1505.31
7           2019-03-01    1                    1505.31
2           2019-01-01    2                    2337.48
5           2019-02-01    2                    2132.17
8           2019-03-01    2                    2132.17
3           2019-01-01    3                    1088.07
6           2019-02-01    3                    1088.07
9           2019-03-01    3                    749.23

Мне нужна логика удаления, которая идентифицирует неизмененные строки и удалениесначала их:

DELETE FROM #Account_Snapshot WHERE Snapshot_Id IN (4,6,7,8)

SELECT * FROM #Account_Snapshot
ORDER BY  Account, Snapshot_Date

Snapshot_Id Snapshot_Date Account              Balance
----------- ------------- -------------------- --------------------
1           2019-01-01    1                    1505.31
2           2019-01-01    2                    2337.48
5           2019-02-01    2                    2132.17
3           2019-01-01    3                    1088.07
9           2019-03-01    3                    749.23

Затем, когда таблица становится намного меньше, мне нужен запрос для создания представления, возможно, с использованием таблицы измерения даты, чтобы иметь возможность получать результаты на лету.

Ответы [ 3 ]

0 голосов
/ 04 февраля 2019

Вот вариант с использованием LAG () , чтобы получить предыдущий баланс для учетной записи, использовать его в подзапросе, а затем вы можете отфильтровать, где баланс равен предыдущему балансу (в основном без изменений), чтобы получитьзаписей, которые вы хотите удалить:

--Show what records to remove
SELECT *
FROM   (
           SELECT *
                , LAG([Balance], 1, 0) OVER ( PARTITION BY [Account]
                                              ORDER BY [Snapshot_Date]
                                            ) AS [PreBalance]
           FROM   [#Account_Snapshot]
       ) AS [p]
WHERE  [p].[Balance] = [p].[PreBalance];

--Then just to delete them
DELETE p
FROM   (
           SELECT *
                , LAG([Balance], 1, 0) OVER ( PARTITION BY [Account]
                                              ORDER BY [Snapshot_Date]
                                            ) AS [PreBalance]
           FROM   [#Account_Snapshot]
       ) AS [p]
WHERE  [p].[Balance] = [p].[PreBalance];

После удаления, чтобы представить данные, как и раньше, да, вам понадобится таблица календаря, из которой строится таблица счетов / дат (комбинация всех учетных записей и всехдаты), а затем перекрестно применить обратно к исходной таблице, чтобы заполнить баланс.

Пример:

--Quick sample calendar table
INSERT INTO [#cal] (
                       [CalDate]
                   )
VALUES ('2019-01-01')
     , ('2019-02-01')
     , ('2019-03-01');

--So this would get us a full list of all accounts and dates based on you calendar table
SELECT     *
FROM       [#cal] [a]
INNER JOIN (
               SELECT DISTINCT [Account]
               FROM   [#Account_Snapshot]
           ) [b]
    ON 1 = 1;

Результаты как:

CalDate     Account
2019-01-01  1
2019-02-01  1
2019-03-01  1
2019-01-01  2
2019-02-01  2
2019-03-01  2
2019-01-01  3
2019-02-01  3
2019-03-01  3

Затем используйте это вподзапрос и перекрестный запрос возвращаются обратно в таблицу счетов для пополнения баланса:

SELECT      *
FROM        (
                SELECT     *
                FROM       [#cal] [a]
                INNER JOIN (
                               SELECT DISTINCT [Account]
                               FROM   [#Account_Snapshot]
                           ) [b]
                    ON 1 = 1
            ) AS [AcctCal]
CROSS APPLY (
                SELECT   TOP 1 [acct].[Balance]
                FROM     [#Account_Snapshot] [acct]
                WHERE    [acct].[Account] = [AcctCal].[Account]
                         AND [acct].[Snapshot_Date] <= [AcctCal].[CalDate]
                ORDER BY [acct].[Snapshot_Date] desc
            ) AS [bal];

Возвращая вам исходные результаты:

CalDate     Account Balance
2019-01-01  1       1505.31
2019-02-01  1       1505.31
2019-03-01  1       1505.31
2019-01-01  2       2337.48
2019-02-01  2       2132.17
2019-03-01  2       2132.17
2019-01-01  3       1088.07
2019-02-01  3       1088.07
2019-03-01  3       749.23
0 голосов
/ 26 апреля 2019

Попробуйте это:

;with cte as (
select *,ROW_NUMBER() over (partition by balance order by Snapshot_Id) rn from #Account_Snapshot
)

Delete from cte where rn > 1
0 голосов
/ 02 февраля 2019

Чтобы определить строки, которые не были изменены, мы можем использовать row_number с разделением в CTE, как показано ниже:

;with cte as (
  select *
 ,ROW_NUMBER() over(partition by [Account],[Balance] order by [Account],Snapshot_Date,[Balance]) [Row]
from #Account_Snapshot 
),DataFiltered  as (select * from cte where cte.[Row]=1  --not a duplicate
),DataDuplicate as (select * from cte where cte.[Row]>1  --any number larger than one is a duplicate
)
   select * from DataFiltered
   ORDER BY  Account, Snapshot_Date

, в результате: -

Snapshot_Id Snapshot_Date   Account Balance Row
1           2019-01-01      1       1505.31 1
2           2019-01-01      2       2337.48 1
5           2019-02-01      2       2132.17 1
3           2019-01-01      3       1088.07 1
9           2019-03-01      3       749.23  1

, чтобы получитьдубликаты данных, мы можем заменить последние две строки на следующие: -

select * from DataDuplicate
ORDER BY  Account, Snapshot_Date

, в результате чего: -

Snapshot_Id Snapshot_Date   Account Balance Row
4           2019-02-01          1   1505.31 2
7           2019-03-01          1   1505.31 3
8           2019-03-01          2   2132.17 2
6           2019-02-01          3   1088.07 2

, чтобы удалить дубликаты данных, мы заменяем последние две строки: -

delete from #Account_Snapshot where Snapshot_Id in (
select Snapshot_Id  from DataDuplicate)

Надеюсь, это поможет.

...