如何运行删除查询,该查询将跳过另一个表的外键引用的记录?

时间:2012-10-03 04:21:22

标签: sql-server

我有一个应用程序通过查询远程API执行大量搜索。结果将被拉入我的数据层(SQL Server),用于查看用户是否希望进一步与它们进行交互。一旦用户开始使用该项目,它必须保留在系统中,但其余结果完全没用,只占用空间。

我正在考虑创建一个运行sproc的任务来删除任何未被另一个表引用的行。有没有办法做到这一点?

另一种措辞方式是:是否有办法执行一个删除语句,该语句会跳过因违反参照完整性而导致错误的行?

编辑:感谢来自@Kos的新信息...... 我正在考虑的备用路径是向表中添加一个位列,如果该行最终被使用并将我的任务删除行标记为false,则将其标记为true。

为清楚起见,以下是对情况的概述。这些语法可能并不完美,但希望你能得到这个想法:

-- Where all the results get pulled down and held (The table I want to clean up every 2 hours or so)
CREATE TABLE [reservations].[DumpTable](
    [utypeID] [bigint] IDENTITY(1,1) NOT NULL
    -- Other columns
    CONSTRAINT [PK_UnitTypesFound] PRIMARY KEY CLUSTERED 
    (
        [utypeID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]


-- This is one of many other tables that might reference the dump table
CREATE TABLE [reservations].[OtherTables](
    [memberID]  INT NOT NULL,
    [utypeID]   BIGINT NOT NULL -- Need to Know if the dumptable is referenced here
    CONSTRAINT [PK_MemberUnitTypes] PRIMARY KEY CLUSTERED
    (
        [memberID],
        [utypeID]
    ) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,     ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

ALTER TABLE [reservations].[OtherTables]  WITH CHECK ADD  CONSTRAINT [FK_OtherTable_DumpTable] FOREIGN KEY([utypeID])
    REFERENCES [reservations].[DumpTable] ([utypeID])

ALTER TABLE [reservations].[OtherTables] CHECK CONSTRAINT [FK_OtherTable_DumpTable]

5 个答案:

答案 0 :(得分:4)

您也可以使用此查询,使用join而不是where子句加速查询。

DELETE FROM DATA_TABLE 
FROM         DATA_TABLE LEFT OUTER JOIN
                      OTHERON DATA_TABLE.OTHER_TABLE_ID= OTHER.ID 
WHERE     (OTHER.ID IS NULL) and DATA_TABLE.SOME_TIMESTAMP < threshold_time

答案 1 :(得分:2)

我今天遇到了同样的问题并最终到了这里。最终我提出了一种不同的方法,更接近劳伦斯寻找IMO的方法,但也可能慢得多,这在我自己的情况下不是问题。

所以基本上我使用游标逐个删除我的行,并且如果发生约束错误,我将delete语句放在try / catch块中以恢复循环:

DECLARE @idc as int
DECLARE Contact_Cursor CURSOR FOR
SELECT ID 
FROM ContactInfo;
OPEN Contact_Cursor;
FETCH NEXT FROM Contact_Cursor INTO @idc 
WHILE @@FETCH_STATUS = 0
  BEGIN
    begin try
      delete from ContactInfo where id = @idc;
      FETCH NEXT FROM Contact_Cursor INTO @idc 
    end try
    begin catch
      FETCH NEXT FROM Contact_Cursor INTO @idc 
    end catch
   END;
CLOSE Contact_Cursor;
DEALLOCATE Contact_Cursor;
GO

答案 2 :(得分:1)

你的问题在细节上有点稀疏,但假设表格看起来像:

DATA_TABLE
    OTHER_TABLE_ID    INTEGER
    SOME_TIMESTAMP    DATETIME

OTHER_TABLE
    ID                INTEGER

然后基本删除如:

DELETE FROM DATA_TABLE dt WHERE dt.SOME_TIMESTAMP < threshold_time
  AND NOT EXISTS (SELECT 1 FROM OTHER TABLE WHERE ID = dt.OTHER_TABLE_ID;

应该做的伎俩。我假设你需要给用户一些时间来决定使用DATA_TABLE中的给定行。

更新: 如果OTHER_TABLE不是特定的表,但可能是几个表中的任何一个,那么最好的选择可能是DATA_TABLE中的一个标志,表示该行正在数据库中的“某处”引用。我看到这种方法的缺点是,如果引用可以在以后消失,那么维护标志会变得更难。

答案 3 :(得分:1)

检查link。这将帮助您获取数据库中的所有外键关系。那里给出的脚本可以只过滤你需要的表格 获得列表后,可以将其转储到临时表中。该表将具有表名和列名,它们之间具有FK关系。然后你必须循环遍历这个表的每个记录并使用动态查询(因为表和列名称将出现在行中),你将不得不在Dump表中找到FK关系中的记录并转储到另一个临时表中。最后删除转储表中所有在此临时表中NOT EXIST的记录 试一试。希望它有所帮助!!

答案 4 :(得分:1)

我最终得到的解决方案类似于@Kos对OP评论中的建议。它有点自然,因为我意识到如果用户交互,这个表的性质至少需要一个引用另一个表的外键,所以类似于BIT列,我只是运行这样的语句:

DELETE FROM [table] WHERE ISNULL([colForeignKey], 0) = 0

对于其他访问者,我建议查看@Maryam的答案,因为我认为大多数登陆此页面的人都是最好的解决方案(至少在发布时已经给出了)。

感谢大家的帮助