1

我有一个表,它的主键“ID”字段在许多其他表中用作外键。

如何检查该表中的特定记录(例如第一条记录“ID = 1”)是否在其他表中使用?

如果在其他表中使用了特定记录,我不想对该行执行任何操作。

4

6 回答 6

2

从表面上看,你的问题没有意义。让我们看一些数据。

users
user_id  user_email
--
1        abc@def.com
2        def@hij.com

user_downloads
user_id  filename  downloaded_starting
1        123.pdf   2013-05-29 08:00:13
1        234.pdf   2013-05-29 08:05:27
1        345.pdf   2013-05-29 08:10:33

user_downloads: 上有一个外键foreign key (user_id) references users (user_id)

只要您不将该外键也声明为ON DELETE CASCADE,那么您就无法删除 users 中的相应行。您不必检查其他表中是否存在行,也不应该. 在一个大系统中,这可能意味着检查数百个表。

如果您不将外键声明为ON UPDATE CASCADE,则如果它被任何其他表引用,则无法更新 user_id。所以,再一次,你不必检查。

如果您使用电子邮件地址作为外键引用的目标,那么再一次,不要使用ON DELETE CASCADE和不要使用ON UPDATE CASCADE. 不要使用这些声明,也不必检查。如果您使用电子邮件地址作为外键引用的目标,那么阻止对其进行更新是没有意义的。

因此,如果您正确构建表格,则无需检查任何内容。

于 2013-05-29T13:08:33.090 回答
2

非常生硬的解决方案:

  • 尝试删除记录。
  • 如果你得到一个完整性约束违规,这意味着它被另一个记录引用,捕获这个异常
  • 如果删除有效,请回滚您的删除

我说这是直言不讳:)

于 2013-05-29T12:46:59.840 回答
1

如果您不想使用试错法,请使用以下方法:

DECLARE @schema NVARCHAR(20)
DECLARE @table NVARCHAR(50)
DECLARE @column NVARCHAR(50)
DECLARE @SQL NVARCHAR(1000)
DECLARE @ID INT
DECLARE @exists INT
DECLARE @x NVARCHAR(100)

SELECT @x = '@exists int output', @ID = 1, @schema = 'dbo', @table = 'Gebruiker', @column = 'GebruikerHasGebruiker_id'

SELECT @SQL = 'SELECT @exists = 1 WHERE EXISTS( ' + STUFF((
    SELECT ' UNION ALL SELECT ' + U2.COLUMN_NAME + ' AS ID FROM ' +  U2.TABLE_SCHEMA + '.' + U2.TABLE_NAME + ' WHERE ' + U2.COLUMN_NAME + ' = ' + cast(@id as VARCHAR(10))
    FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS R INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE U ON R.UNIQUE_CONSTRAINT_NAME = U.CONSTRAINT_NAME 
    INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE U2 ON R.CONSTRAINT_NAME = U2.CONSTRAINT_NAME
    WHERE U.TABLE_SCHEMA = @schema
    AND U.TABLE_NAME = @table
    AND U.COLUMN_NAME = @column
    FOR XML PATH('')
    ),1,11, '') + ')'

EXEC sp_executesql @SQL, @x, @exists = @exists OUTPUT

IF 1 <> @exists
BEGIN
  -- do you stuff here
END

但在 99% 的情况下,你可以这样做,这太过分了。如果您已经知道 FK 并且只创建一个查询,则速度会更快。

编辑:一点解释。此动态 SQL 在 INFORMATION SCHEMA 中查找与其他表的所有关系。它使用该信息创建查询以检查您的 ID 是否存在于该表中。使用 UNION,它会添加所有结果,如果找到任何结果,则返回 1。这可以用于任何数据库、任何列,只要您不检查多个列的 FK。

于 2013-05-29T13:32:25.497 回答
1

您可以使用触发器回滚任何提供 true 的事务

"where exists( select * from otherTable Where fk = id union select * from anotherTable Where fk = id union etc)

如果您在每个以 fk 开头的表上都有任何索引,它不会太重(无论如何您应该有一般速度),SQL 只会检查索引的 id。即对每个检查的表进行一次读取。

于 2013-05-29T12:47:00.933 回答
0

使用此解决方案,您无需对所有引用的表进行硬编码。

use tempdb
 go
/* provide test data*/
if OBJECT_ID(N't2') is not null
    drop table t2
if OBJECT_ID(N't1') is not null
    drop table t1

create table t1(i int  not null primary key)
create table t2(i int not null, constraint fk_t1_t2 foreign key (i) references t1(i))

go

insert into t1 values(1),(2)
insert into t2 values(1)
/* checking if the primary key value referenced in other tables */
declare @forCheck int=1 /* id to be checked if it referenced in other tables */
declare @isReferenced bit=0

begin tran
    begin try
        delete from t1 where i=@forCheck
    end try
    begin catch
        set @isReferenced=1
    end catch

rollback

select @isReferenced
于 2013-05-29T12:54:24.640 回答
0

该方法应该是收集所有依赖对象并查询它们以检查父表记录是否存在。

我使用返回依赖对象的过程。我无法发布该程序的原因是超过限制的 30000 个字符来发布它是 48237 个字符。让我知道您的邮件 ID,我会将程序发送给您。

遍历该过程的结果以检查是否有任何依赖列包含您的主表数据。

于 2013-05-29T15:12:18.233 回答