2012-05-30 3 views
4

Есть ли способ удалить все строки в таблице, кроме одной (случайной) строки, без указания имен столбцов в инструкции DELETE?DELETE EXCEPT TOP 1

Я пытаюсь сделать что-то вроде этого:

CREATE TABLE [dbo].[DeleteExceptTop1]([Id] INT) 
INSERT [dbo].[DeleteExceptTop1] SELECT 1 
INSERT [dbo].[DeleteExceptTop1] SELECT 2 
INSERT [dbo].[DeleteExceptTop1] SELECT 3 

SELECT * FROM [dbo].[DeleteExceptTop1] 

DELETE 
FROM [dbo].[DeleteExceptTop1] 
EXCEPT 
SELECT TOP 1 * FROM [dbo].[DeleteExceptTop1] 

SELECT * FROM [dbo].[DeleteExceptTop1] 

Окончательный SELECT должен дать один ряд (может быть любой из трех).

+0

Вы пытаетесь выбрать одну случайную строку или пытаться удалить из таблицы все, кроме одной случайной строки? – Bill

+0

@Bill - последний.Спасибо –

+0

В таблице есть ПК? Если это так просто, где PK! = (Выберите max (PK)) – Paparazzi

ответ

5
;WITH CTE AS 
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT newid())) AS RN 
FROM [dbo].[DeleteExceptTop1] 
) 
DELETE FROM CTE 
WHERE RN > 1 

Или аналогично @ abatishchev отвечает, но с большим разнообразием в заказе и избежать устаревших конструкций.

DECLARE @C INT 
SELECT @C = COUNT(*) - 1 
FROM [dbo].[DeleteExceptTop1] 

IF @c > 0 
BEGIN 
WITH CTE AS 
(
SELECT TOP(@C) * 
FROM [dbo].[DeleteExceptTop1] 
ORDER BY NEWID() 
) 
DELETE FROM CTE; 
END 

Или последний способ, который использует EXCEPT и не принимает на себя никаких повторяющихся строк и что все столбцы из типов данных, совместимых с оператором EXCEPT

/*Materialise TOP 1 to ensure only evaluated once*/ 
SELECT TOP(1) * 
INTO #T 
FROM [dbo].[DeleteExceptTop1] 
ORDER BY NEWID() 

;WITH CTE AS 
(
SELECT * 
FROM [dbo].[DeleteExceptTop1] T1 
WHERE EXISTS(
      SELECT * 
      FROM #T 
      EXCEPT 
      SELECT T1.*) 
) 
DELETE FROM CTE; 

DROP TABLE #T 
+0

Итак, вы все равно должны указать имя столбца, только чтобы создать его в CTE – Magnus

+0

@Magnus - True! –

+0

+1 но у меня было такое же философское возражение, как и @Magnus – Matthew

2


Чтобы определить, какие строки вы хотите удалить, вам необходимо использовать имя столбца (например, первичного ключа).

«Случайная строка» не имеет смысла в SQL, кроме его данных. Если вы хотите, чтобы удалить все, кроме некоторые строки, необходимо дифференцировать эту строку от других, вы с к DELETE

EXCEPT работ путем сравнения DISTINCT значения в строке.

EDIT:Если вы можете указать первичный ключ, то это пустяк. Вы можете просто DELETE, где PK <> ваш «случайный» выбор илиNOT IN ваш «случайный» выбор (ы).

EDIT: Видимо я неправ о необходимости указать любое имя колонки, вы можете сделать это с помощью присвоенного ROW_NUMBER .. Но я не собираюсь, чтобы удалить мой ответ, потому что он ссылается на использование вами EXCEPT, который обсуждался в комментариях. Вы не можете сделать это без вытекающих некоторого имени столбца, как, что из ROW_NUMBER

1

Вы могли бы сделать что-то вроде этого (SQL 2008)

DECLARE @Original TABLE ([Id] INT) 
INSERT INTO @Original(ID) VALUES(1) 
INSERT INTO @Original(ID) VALUES(2) 
INSERT INTO @Original(ID) VALUES(3) 

SELECT * FROM @Original; 

WITH CTE AS 
(SELECT ROW_NUMBER() OVER(ORDER BY ID) AS ROW, ID FROM @Original) 
DELETE @Original 
FROM @Original O 
INNER JOIN CTE ON O.ID = CTE.ROW 
WHERE ROW > 1 

SELECT * FROM @Original 
3

Try:

declare @c int 
select @c = count(*) - 1 from [dbo].[DeleteExceptTop1] 

IF @c > 0 
BEGIN 

set RowCount @c 

delete from [dbo].[DeleteExceptTop1] 
END 
+0

«Использование SET ROWCOUNT не влияет на операторы DELETE, INSERT и UPDATE в следующей версии SQL Server. Избегайте использования SET ROWCOUNT вместе с инструкциями DELETE, INSERT и UPDATE в новых разработках и планируете изменять приложения, которые в настоящее время используют его «. - http://msdn.microsoft.com/en-us/library/ms188774(v=sql.90).aspx –

+0

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

+0

Редактирование @MartinSmith - это хороший ответ. Тем не менее, минорная нитьпик - это то, что теперь удаляет «нижнюю» случайную строку, а не случайную строку «TOP». – Matthew

0

Кажется, что самый простой ответ может быть лучшим. Должно работать следующее:

Declare @count int 
Set @count=(Select count(*) from DeleteExceptTop1)-1 
Delete top (@count) from DeleteExceptTop1 
0

Я знаю, что на это ответили, но что?

DELETE 
FROM [dbo].[DeleteExceptTop1] 
Where Id not in (
SELECT TOP 1 * FROM [dbo].[DeleteExceptTop1]) 
+0

"без указания имен столбцов в инструкции DELETE". –

+0

Возможно, вам не нужно, если вы удаляете всю строку. (на SQL Server 2008) – chris