В SQL Server 2000, как удалить указанные строки в таблице, которая не имеет первичного ключа? - PullRequest
2 голосов
/ 07 января 2011

Допустим, у нас есть таблица с некоторыми данными.

IF OBJECT_ID('dbo.table1') IS NOT NULL
BEGIN
    DROP TABLE dbo.table1;
END
CREATE TABLE table1 ( DATA INT );

---------------------------------------------------------------------
-- Generating testing data
---------------------------------------------------------------------
INSERT INTO dbo.table1(data)
SELECT 100
UNION ALL
SELECT 200
UNION ALL
SELECT NULL
UNION ALL
SELECT 400
UNION ALL
SELECT 400
UNION ALL
SELECT 500
UNION ALL
SELECT NULL;

Как удалить 2-ю, 5-ю, 6-ю записи в таблице?Порядок определяется следующим запросом.

SELECT  data
FROM    dbo.table1
ORDER BY data DESC;

Обратите внимание, это в среде SQL Server 2000 .

Спасибо.

Ответы [ 4 ]

3 голосов
/ 07 января 2011

Короче говоря, вам нужно что-то в таблице, чтобы указать последовательность. «2-й ряд» не является последовательным, когда нет ничего, что навязывает последовательность. Тем не менее, возможное решение может быть (игрушка пример => игрушка решение):

If object_id('tempdb..#NumberedData') Is Not Null
    Drop Table #NumberedData

Create Table #NumberedData
(
Id int not null identity(1,1) primary key clustered
, data int null
)

Insert #NumberedData( data )
SELECT 100
UNION ALL SELECT 200
UNION ALL SELECT NULL
UNION ALL SELECT 400
UNION ALL SELECT 400
UNION ALL SELECT 500
UNION ALL SELECT NULL

Begin Tran

Delete table1

Insert table1( data )
Select data
From #NumberedData
Where Id Not In(2,5,6)

If @@Error <> 0 
    Commit Tran
Else 
    Rollback Tran

Очевидно, что этот тип решения не гарантированно работает точно так, как вы хотите, но концепция - это лучшее, что вы получите. По сути, вы помещаете свои строки в таблицу со столбцом идентификаторов и используете его для идентификации удаляемых строк. Удаление строк влечет за собой очистку исходной таблицы и повторное заполнение только теми строками, которые вы хотите. Без какого-либо уникального ключа просто не существует чистого способа решения этой проблемы.

2 голосов
/ 07 января 2011

Как вы, вероятно, знаете, вы можете сделать это в более поздних версиях, используя row_number очень просто.

delete t from 
(select ROW_NUMBER() over (order by data) r from table1) t   
where r in (2,5,6)

Даже без этого можно использовать недокументированную функцию %%LOCKRES%%, чтобы различать 2 одинаковых строки

SELECT data,%%LOCKRES%%
FROM dbo.table1`

Я не думаю, что это доступно в SQL Server 2000, хотя.

В наборах SQL нет порядка, но у курсоров есть, чтобы вы могли использовать что-то вроде ниже. NB: Я ожидал, что смогу использовать DELETE ... WHERE CURRENT OF, но это зависит от PK, поэтому код для удаления строки не так прост, как я надеялся.

В случае, если удаляемые данные являются дубликатами, нет гарантии, что они удалят ту же строку, что и CURRENT OF. Однако в этом случае порядок связанных строк в любом случае является произвольным, поэтому любой удаляемый ряд мог бы с одинаковым успехом получить этот номер строки в порядке курсора.

DECLARE @RowsToDelete TABLE
(
rowidx INT PRIMARY KEY
)
INSERT INTO @RowsToDelete SELECT 2 UNION SELECT 5 UNION SELECT 6

DECLARE @PrevRowIdx int
DECLARE @CurrentRowIdx int
DECLARE @Offset int
SET @CurrentRowIdx = 1
DECLARE @data int

DECLARE ordered_cursor  SCROLL CURSOR FOR
SELECT data
FROM dbo.table1
ORDER BY data

OPEN ordered_cursor

FETCH NEXT FROM ordered_cursor INTO @data

WHILE EXISTS(SELECT * FROM @RowsToDelete)
BEGIN
SET @PrevRowIdx = @CurrentRowIdx
SET @CurrentRowIdx = (SELECT TOP 1 rowidx FROM @RowsToDelete ORDER BY rowidx)
SET @Offset = @CurrentRowIdx - @PrevRowIdx
DELETE FROM @RowsToDelete WHERE rowidx = @CurrentRowIdx

FETCH RELATIVE @Offset FROM ordered_cursor INTO @data

/*Can't use DELETE ... WHERE CURRENT OF as here that requires a PK*/
SET ROWCOUNT 1
DELETE FROM dbo.table1 WHERE (data=@data OR data IS NULL OR @data IS NULL)
SET ROWCOUNT 0

END

CLOSE ordered_cursor
DEALLOCATE ordered_cursor
0 голосов
/ 07 января 2011

Вы планируете заранее, и если вы предполагаете, что это возможно, вы добавляете столбец суррогатного ключа или что-то подобное.

Как правило, вы не создаете таблицы без ПК.

Это все равно что спросить: «Скажи, что я не смотрю в обоих направлениях, прежде чем переходить дорогу, и ступаю перед автобусом».

0 голосов
/ 07 января 2011

Чтобы выполнить какое-либо действие с набором строк (например, удалить их), вам необходимо знать, что идентифицирует эти строки.

Итак, вам нужно придумать критерии, которые идентифицируют строки, которые вы хотите удалить.

Предоставление примера с игрушкой, подобного приведенному выше, не особенно полезно.

...