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

发布于 2024-10-10 23:11:52 字数 677 浏览 4 评论 0原文

假设我们有一个表,其中包含一些数据。

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

谢谢。

Let's say we have a table with some data in it.

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;

How to delete the 2nd, 5th, 6th records in the table? The order is defined by the following query.

SELECT  data
FROM    dbo.table1
ORDER BY data DESC;

Note, this is in SQL Server 2000 environment.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

∞琼窗梦回ˉ 2024-10-17 23:11:52

简而言之,您需要表中的某些内容来指示顺序。当没有任何东西强制顺序时,“第二行”是不合逻辑的。然而,一个可能的解决方案可能是(玩具示例=>玩具解决方案):

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

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

In short, you need something in the table to indicate sequence. The "2nd row" is a non-sequitur when there is nothing that enforces sequence. However, a possible solution might be (toy example => toy solution):

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

Obviously, this type of solution is not guaranteed to work exactly as you want but the concept is the best you will get. In essence, you stuff your rows into a table with an identity column and use that to identify the rows to remove. Removing the rows entails emptying the original table and re-populating with only the rows you want. Without a unique key of some kind, there just is no clean way of handling this problem.

手心的海 2024-10-17 23:11:52

您可能知道,您可以在更高版本中使用 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 (data=@data OR data IS NULL OR @data IS NULL)
SET ROWCOUNT 0

END

CLOSE ordered_cursor
DEALLOCATE ordered_cursor

As you are probably aware you can do this in later versions using row_number very straightforwardly.

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

Even without that it is possible to use the undocumented %%LOCKRES%% function to differentiate between 2 identical rows

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

I don't think that's available in SQL Server 2000 though.

In SQL Sets don't have order but cursors do so you could use something like the below. NB: I was expecting to be able to use DELETE ... WHERE CURRENT OF but that relies on a PK so the code to delete a row is not as simple as I was hoping for.

In the event that the data to be deleted is a duplicate then there is no guarantee that it will delete the same row as CURRENT OF would have. However in this eventuality the ordering of the tied rows is arbitrary anyway so whichever row is deleted could equally well have been given that row number in the cursor ordering.

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
好久不见√ 2024-10-17 23:11:52

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

因此,必须提出确定要删除的行的标准。

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

To perform any action on a set of rows (such as deleting them), you need to know what identifies those rows.

So, you have to come up with criteria that identifies the rows you want to delete.

Providing a toy example, like the one above, is not particularly useful.

天涯离梦残月幽梦 2024-10-17 23:11:52

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

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

这就像问“假设我在过马路之前没有向两个方向看,然后我就走到了一辆公共汽车前面”。

You plan ahead and if you anticipate this is possible you add a surrogate key column or some such.

In general you make sure you don't create tables without PK's.

It's like asking "Say I don't look both directions before crossing the road and I step in front of a bus."

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文