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

Tsql 在SQL Server 2000中,如何删除没有主键的表中的指定行?,tsql,sql-server-2000,ranking,Tsql,Sql Server 2000,Ranking,假设我们有一个包含一些数据的表 IF OBJECT_ID('dbo.table1') IS NOT NULL BEGIN DROP TABLE dbo.table1; END CREATE TABLE table1 ( DATA INT ); --------------------------------------------------------------------- -- Generating testing data --------------------------

假设我们有一个包含一些数据的表

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环境中进行的


谢谢。

要对一组行执行任何操作(如删除行),您需要知道哪些行可以标识这些行

因此,您必须提出标识要删除的行的标准


提供一个玩具示例,如上面的示例,并不是特别有用。

您可能知道,在以后的版本中,您可以非常直接地使用row_number来完成此操作

delete t from 
(select ROW_NUMBER() over (order by data) r from table1) t   
where r in (2,5,6)
即使没有此功能,也可以使用未记录的%%LOCKRES%%函数来区分两个相同的行

SELECT data,%%LOCKRES%%
FROM dbo.table1`
不过,我认为在SQLServer2000中不可用

在SQL集合中,并没有顺序,但游标有顺序,所以您可以使用如下内容。注:我希望能够使用删除。。。其中当前是,但这依赖于PK,因此删除行的代码并不像我希望的那么简单

如果要删除的数据是重复的,则不能保证它将删除与当前的相同的行。然而,在这种情况下,绑定行的顺序是任意的,因此无论删除哪一行,都可以在光标顺序中给出该行号

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

您可以提前计划,如果您预期这是可能的,您可以添加一个代理键列或类似的列

通常,您要确保不创建没有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

显然,这种类型的解决方案不能保证完全按照您想要的方式工作,但它的概念是您将得到的最佳解决方案。本质上,您可以将行填充到具有标识列的表中,并使用该列标识要删除的行。删除这些行需要清空原始表并仅重新填充所需的行。如果没有某种类型的唯一键,就没有处理此问题的干净方法。

您的数据库模式不可能是这样的。正如@Mitch Wheat所说的——请尝试提供您的真实场景,否则您会让我们的生活变得更加困难。如果没有主键,它就不是一张表!Joe Celko-添加一个主键,您的所有问题就会神奇地消失……我+1这样做是因为它实现了相同的目标,但它没有回答如何仅删除特定行的问题。