我有一个表,它的主键“ID”字段在许多其他表中用作外键。
如何检查该表中的特定记录(例如第一条记录“ID = 1”)是否在其他表中使用?
如果在其他表中使用了特定记录,我不想对该行执行任何操作。
我有一个表,它的主键“ID”字段在许多其他表中用作外键。
如何检查该表中的特定记录(例如第一条记录“ID = 1”)是否在其他表中使用?
如果在其他表中使用了特定记录,我不想对该行执行任何操作。
从表面上看,你的问题没有意义。让我们看一些数据。
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
. 不要使用这些声明,也不必检查。如果您不使用电子邮件地址作为外键引用的目标,那么阻止对其进行更新是没有意义的。
因此,如果您正确构建表格,则无需检查任何内容。
非常生硬的解决方案:
我说这是直言不讳:)
如果您不想使用试错法,请使用以下方法:
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。
您可以使用触发器回滚任何提供 true 的事务
"where exists( select * from otherTable Where fk = id union select * from anotherTable Where fk = id union etc)
如果您在每个以 fk 开头的表上都有任何索引,它不会太重(无论如何您应该有一般速度),SQL 只会检查索引的 id。即对每个检查的表进行一次读取。
使用此解决方案,您无需对所有引用的表进行硬编码。
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
该方法应该是收集所有依赖对象并查询它们以检查父表记录是否存在。
我使用返回依赖对象的过程。我无法发布该程序的原因是超过限制的 30000 个字符来发布它是 48237 个字符。让我知道您的邮件 ID,我会将程序发送给您。
遍历该过程的结果以检查是否有任何依赖列包含您的主表数据。