2015-07-06 2 views
0

Я использую базу данных MS SQL и у меня есть таблица с именем «Журналы», который выглядит следующим образом: добавленыУдалить все строки, за исключением 100 самых последних

enter image description here

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

Что мне нужно делать периодически, это немного очистки. То есть Мне нужен SQL-запрос, который удаляет старые строки и сохраняет только самые последние 100 записей в этой таблице.

Я согласен, было бы лучше, чтобы он «удалить записи старше some_date» ... Это было, как это раньше, но клиент хочет это разные :(Так что ... вот мы.

BTW : Я немного разочаровываю в том, что люди бросают негативы на этот вопрос. Есть ли что-то не так с этим или что? ... Представьте себе: этот вопрос произвел уже 4 ответа !!! ... и один парень решил выбросить отрицательный на этом! Теперь я действительно не знаю, что думать ... Странные люди здесь :(

+0

что вам нужно сделать? удалить старые записи или удалить все записи, кроме последних 100? что произойдет, если вы заработаете 101 отчет за одну секунду? означает ли это, что вы пропустите первую запись? – Kritner

+0

Есть ли идентификатор или что-нибудь, что делает строку уникальной? –

+1

Дисковое пространство настолько дешево в эти дни, что я бы спорил с строками такого размера, ничего не нужно было бы удалять. Если вам когда-либо *** нужно было удалить ***, я бы не удалял на основе «оставить все оставшиеся записи», а скорее «удаляет записи старше х даты».« – Kritner

ответ

3

Вы можете использовать следующий запрос:

-- Step 3: delete records older than the datetime below 
DELETE FROM Logs WHERE DateTime < (
    -- Step 2: select oldest datetime from below 
    SELECT MIN(DateTime) FROM (
     -- Step 1: select top 100 most recent datetime 
     SELECT TOP 100 DateTime FROM Logs ORDER BY DateTime DESC 
    ) AS dontcare 
) 

Или это тот, который требует первичного ключа:

DELETE FROM Logs WHERE id NOT IN (
    SELECT TOP 100 id FROM Logs ORDER BY DateTime DESC 
) 

А если нет первичного ключа, и вы используете SQL Server 2012, то вы можете использовать OFFSET FETCH, чтобы выбрать все строки, начиная с 101, в общее табличное выражение и удалить их:

-- BEGIN TRANSACTION 
-- SELECT COUNT(*) FROM Logs 
; WITH CTE AS (
    SELECT * FROM Logs ORDER BY DateTime DESC OFFSET 100 ROWS 
) 
DELETE FROM CTE 
-- SELECT COUNT(*) FROM Logs 
-- ROLLBACK 

Или в более старых версиях:

-- BEGIN TRANSACTION 
-- SELECT COUNT(*) FROM Logs 
; WITH CTE AS (
    SELECT ROW_NUMBER() OVER(ORDER BY DateTime DESC) AS RN, Logs.* FROM Logs 
) 
DELETE FROM CTE WHERE RN > 100 
-- SELECT COUNT(*) FROM Logs 
-- ROLLBACK 
+0

Не могли ли последние работать с столбцом [DateTime] как тоже? – Matt

+0

Хорошо p oint, да, он также будет работать с DateTime вместо id. –

+0

@SalmanA: Что делать, если есть больше записей с DateTime = MIN (DateTime) ...? Я думаю, что после выполнения запроса можно получить менее 100 строк (первое, о чем я говорю). Правильно? –

3

Хотя я согласен с другими, что это, вероятно, не путь, вот способ сделать это в любом случае:

;WITH keepers AS 
( SELECT TOP 100 [DateTime] 
    FROM dbo.Logs 
    ORDER BY [DateTime] DESC) 
DELETE FROM dbo.Logs a 
WHERE NOT EXISTS (SELECT 1 FROM keepers b WHERE b.[DateTime] = a.[DateTime]) 
+0

Не работает: он говорит: «Msg 156, Level 15, State 1, Line 1 Неправильный синтаксис рядом с ключевым словом« NOT ». –

+0

Хорошо, он работает после некоторых незначительных исправлений, но я продолжаю считать 101 запись каждый раз, когда я выполняю запрос ... –

+0

Любые повторяющиеся значения [DateTime]? – Matt

2

Вместо использования NOT EXISTS, просто использовать >=:

WITH keepers AS (
    SELECT TOP 100 [DateTime] 
    FROM dbo.Logs 
    ORDER BY [DateTime] DESC 
    ) 
DELETE FROM dbo.Logs a 
    WHERE l.DateTime < (SELECT MIN([DateTime]) FROM keepers); 

Я не уверен, если есть блокировка настроек, где новые строки могут быть добавлены в то время как запущен delete. Если это так, это все равно будет безопасным для этого.

Вы можете реально упростить это в SQL Server 2012+:

DELETE FROM dbo.Logs a 
    WHERE l.DateTime < (SELECT [DateTime] 
         FROM dbo.logs 
         ORDER BY [DateTime] 
         OFFSET 99 FETCH FIRST 1 ROW ONLY 
         ); 
+0

Я пробовал первый, но он не работает. –

+0

Хорошо, это работает после некоторых незначительных исправлений (отсутствующих скобок и т. Д.) –

0
DECLARE @cutoff DATETIME 
SELECT TOP 100 @cutoff = [DateTime] FROM Logs ORDER BY [DateTime] DESC 
DELETE FROM Logs WHERE [DateTime] < @cutoff 
0

Это работает для меня:

;with cte as(select top(select count(*) - 100 from table) * from table order by dt) 
delete from cte 
+0

Но я думаю, что это не сработает, если в какой-то момент счетчик (*) будет меньше 100, т. Е. Выберите НЕГАТИВНОЕ количество строк/записей ... –