SQL Server - 删除未使用的行

时间:2010-08-24 04:42:30

标签: sql-server tsql

我需要获取存储过程(不是标准,只有自定义)来删除未使用的行表(table1)和其他一些表(table2,table3,table4 ......- 我们不知道有多少个表引用to table1 by FOREIGN KEY CONSTRAINT )可以引用此表。

例如:

СREATE PROCEDURE [dbo].[delete_on_constraints]
@table varchar(36) – table name we need to delete unused rows
@column varchar(36) – column name - primary key, on which other tables refers by FOREIGN KEY CONSTRAINT

有table1和table2,table3引用table1(提醒,我们不知道有多少表通过FOREIGN KEY CONSTRAINT引用table1)

CREATE TABLE [table1] (
    [id] [int] IDENTITY (1, 1) NOT NULL CONSTRAINT [PK_ table1] PRIMARY KEY,
    [value] [int] NULL 
)
GO

CREATE TABLE [table2] (
    [id] [int] IDENTITY (1, 1) NOT NULL CONSTRAINT [PK_ table2] PRIMARY KEY,
    [table1_id] [int] NOT NULL ,
       CONSTRAINT [FK_ table2_ table1] FOREIGN KEY ([table1_id]) REFERENCES [table1] ( [id] ) 
) 
GO 

CREATE TABLE [table3] (
    [id] [int] IDENTITY (1, 1) NOT NULL CONSTRAINT [PK_ table3] PRIMARY KEY,
    [table1_id] [int] NOT NULL ,
       CONSTRAINT [FK_ table3_ table1] FOREIGN KEY ([table1_id]) REFERENCES [table1] ( [id] ) 
)

GO 
INSERT INTO [table1] VALUES (100)
INSERT INTO [table1] VALUES (200)
INSERT INTO [table1] VALUES (300)
INSERT INTO [table1] VALUES (400)

GO
INSERT INTO [table2] VALUES (1)
INSERT INTO [table2] VALUES (3)

GO
INSERT INTO [table3] VALUES (1)
INSERT INTO [table3] VALUES (2)
INSERT INTO [table3] VALUES (3)

之前的行调用存储过程

table1
id value
1 100
2 200
3 300
4 400

table2
id table1_id
1 1
2 3

table3
id table1_id
1 1
2 2
3 3

之后 [dbo]。[delete_on_constraints]'table1''id'程序调用

table1

id       value
1        100
2        200
3        300

1 个答案:

答案 0 :(得分:1)

首先,让我说明该代码绝不应该用于生产。我的意思是,它应该只用作一次性清理。如果您经常需要在不知道DRI的情况下删除行,那么就存在一个基本的设计问题。

简而言之,您需要使用动态SQL来查询关系并构建Delete语句。

Declare @Columns Cursor
Declare @PKTableSchema nvarchar(128)
Declare @PKTableName nvarchar(128)
Declare @PKColumnName nvarchar(128)
Declare @TableSchema nvarchar(128)
Declare @TableName nvarchar(128)
Declare @ColumnName nvarchar(128)
Declare @Sql nvarchar(max)

Set @Columns = Cursor Fast_Forward For
    Select Quotename(PK_CCU.TABLE_SCHEMA)
        , Quotename(PK_CCU.TABLE_NAME)
        , Quotename(PK_CCU.COLUMN_NAME)
        , Quotename(RC_CCU.TABLE_SCHEMA)
        , Quotename(RC_CCU.TABLE_NAME)
        , Quotename(RC_CCU.COLUMN_NAME)
    From INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS As RC
        Join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE As RC_CCU
            On RC_CCU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA
                And RC_CCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
        Join INFORMATION_SCHEMA.TABLE_CONSTRAINTS As TC
            On TC.CONSTRAINT_SCHEMA = RC.UNIQUE_CONSTRAINT_SCHEMA
                And TC.CONSTRAINT_NAME = RC.UNIQUE_CONSTRAINT_NAME
                And TC.CONSTRAINT_TYPE = 'PRIMARY KEY'
        Join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE As PK_CCU
            On PK_CCU.CONSTRAINT_SCHEMA = TC.CONSTRAINT_SCHEMA
                And PK_CCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME
    Where PK_CCU.TABLE_SCHEMA = 'dbo'
        And PK_CCU.TABLE_NAME = @TableParam
        And PK_CCU.COLUMN_NAME = @ColumnParam

Open @Columns 
Fetch Next From @Columns Into @PKTableSchema, @PKTableName, @PKColumnName, @TableSchema, @TableName, @ColumnName

Set @Sql = 'Delete ' + @PKTableSchema + '.' + @PKTableName 
    + ' Where 1 = 1' 

While @@Fetch_Status = 0
Begin
    Set @Sql = @Sql + Char(13) + Char(10)
        + ' And Not Exists ( Select 1 From ' + @TableSchema + '.' + @TableName
                            + ' Where ' + @ColumnName + ' = ' + @PKTableSchema + '.' + @PKTableName + '.' + @PKColumnName
                            + ')'
    Fetch Next From @Columns Into @PKTableSchema, @PKTableName, @PKColumnName, @TableSchema, @TableName, @ColumnName
End

Close @Columns
Deallocate @Columns

--Print @Sql
Exec( @Sql )
不过,我还要提一下,更好的解决方案可能是在您的关系中启用Cascade Delete。通过级联删除,对此例程的需求没有实际意义。

有关详情,请参阅Cascading Referential Integrity Constraints