在SQL Server 2000中,如何删除没有主键的表中的指定行?

问题描述:

假设我们有一张包含一些数据的表格。在SQL Server 2000中,如何删除没有主键的表中的指定行?

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中环境。

谢谢。

+1

你的数据库模式不可能是这样的。正如@米奇小麦所说 - 请尽量提供你真实的情景,否则你的生活会变得比他们的生活更困难。 – RPM1984 2011-01-07 04:36:19

+1

*如果它没有主键,它不是一张桌子!*(Joe Celko) - 添加一个主键,所有问题都会自动消失...... – 2011-01-07 07:45:04

正如你可能知道你可以在以后的版本中使用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集没有顺序,但游标这样做,你可以使用类似下面的东西。注:我期望能够使用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 ([email protected] OR data IS NULL OR @data IS NULL) 
SET ROWCOUNT 0 

END 

CLOSE ordered_cursor 
DEALLOCATE ordered_cursor 

要对一组行执行任何操作(例如删除它们),您需要知道标识这些行的标识。

因此,必须拿出标识你想删除的行的标准。

提供一个玩具的例子,就像上面的例子一样,并不是特别有用。

你提前计划,如果你预计这是可能的,你可以添加一个代理键列或其他类似的东西。

一般来说,您一定要确保不创建没有PK的表格。

这就像问道:“说我在过马路之前看不到两个方向,我走在公共汽车前面。”

总之,你需要表中的东西来表示顺序。当没有任何东西强制顺序的时候,“第二排”是一个不起作用的东西。然而,一个可能的解决方案(例如玩具=>玩具溶液):

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 

显然,这种类型的解决方案不能保证准确地工作,只要你想,但这个概念是,你会得到最好的。实质上,您可以将行填入具有标识列的表中,并使用它来标识要删除的行。删除行需要清空原始表并仅使用所需的行重新填充。没有某种独特的钥匙,就没有办法解决这个问题。