如果一个值不在另一个表中,如何防止插入到SQL Server表中?

如果一个值不在另一个表中,如何防止插入到SQL Server表中?,sql,sql-server,tsql,triggers,check-constraints,Sql,Sql Server,Tsql,Triggers,Check Constraints,假设我有两个SQL Server表。其中一个包含瞬态数据—记录会随着填充表的外部数据的更改而插入、更新和删除 我有另一个使用该表中数据的表,我需要确保在尝试插入时在该表中找到一个列值 表1-小部件: 表2-交易: 所以在上面的例子中,我需要确保widget_id在dbo.Widgets中,否则会抛出错误。我不能从事务到小部件使用外键,因为事务记录是永久性的,当尝试删除小部件时,它将失败,因为它被外键引用 我可以使用检查约束在插入之前在Widgets表中查找值吗?或者可能是一个触发器查找该值,如果

假设我有两个SQL Server表。其中一个包含瞬态数据—记录会随着填充表的外部数据的更改而插入、更新和删除

我有另一个使用该表中数据的表,我需要确保在尝试插入时在该表中找到一个列值

表1-小部件:

表2-交易:

所以在上面的例子中,我需要确保widget_id在dbo.Widgets中,否则会抛出错误。我不能从事务到小部件使用外键,因为事务记录是永久性的,当尝试删除小部件时,它将失败,因为它被外键引用

我可以使用检查约束在插入之前在Widgets表中查找值吗?或者可能是一个触发器查找该值,如果该值不存在,则抛出一个错误?我不知道这两种方法是如何工作的,以及可能的性能影响是什么。在这里寻找最佳实践

提前谢谢

外键是一种检查约束。我建议您在INSERT语句中添加EXISTS子句,这样就不会插入不希望插入的行。在伪SQL中,这将是:

插入dbo.Transactions小部件\u id、事务\u数据\u 1 选择widget\u id, 事务处理数据1 从值…Vwidget\u id,事务\u数据\u 1 在存在的位置选择1 来自dbo.w 其中w.widget_id=v.widget_id; 如果需要抛出错误,可以使用如下触发器,只需注意,如果表小部件中不存在任何一个值,则整个插入都将失败:

创建触发器dbo.trg_fk_transasctionwidget 关于dbo.Transactions 插入后 像 如果存在,请选择1 从插入i 左连接i.widget\u id=w.widget\u id上的dbo.widgets w 其中w.widget_id为空 -将错误号更改为适合您的环境的错误号 抛出73246,N'INSERT语句与触发器约束trg_fk_transasctionWidget冲突。冲突发生在表dbo.Transactions,列widget_id',16; 去
不过,像@MartinSmith一样,您似乎真的应该考虑级联。

外键是最佳实践。一旦你决定不这样做,你就脱离了最佳实践。您可以使用一个包含UDF的检查约束来进行查找,也可以使用一个触发器,但更好的方法是更深入地了解两个表中的行是如何来的,以及为什么只在插入时检查而不在插入后检查是一个有用的路径。当删除相应的小部件时,将小部件_id保留在其中的值是什么?外键和级联在删除时将其设置为null对您有效吗?@SMor外键是最好的做法,如果它在这种情况下有效,但在这种情况下不起作用。我无法从窗口小部件中删除行。@事务数据是永久数据,需要在删除窗口小部件记录后保留。当小部件记录被删除时,它随后被添加到另一个具有永久数据的表中。事务数据是需要保存的历史信息。这就是把它留在那里的价值所在。然后,也许你应该先填充你的永久widgets表@EricBelair,然后将数据插入到你的事务中。那么外键就可以工作了。这里的问题似乎是设计,因此你需要重新设计轮子。好主意,但是,我无法更改insert语句。插入是从外部应用程序进行的。“我只能控制我这边的事情。这个答案有两个解决方案,@EricBelair。”。触发器也存在。我需要担心触发器是否存在任何风险/性能影响?很可能存在性能影响,是的@EricBelair;尤其是如果表dbo.widget中的widget_id没有索引,或者插入的行数非常大。但是,如果您担心此问题,请使用外键;正如我们都告诉过你的那样,这正是你真正需要的。正如我在帖子中所说,外键不起作用。当尝试在窗口小部件上删除行时,如果在事务中找到对应的记录(即永久数据),则删除将失败。
CREATE TABLE [dbo].[Widgets]
(
    [id] [int] NOT NULL,
    [widget_attr_1] [int] NULL,
    [widget_attr_2] [varchar](10) NOT NULL,

    CONSTRAINT [PK_Table_1] 
        PRIMARY KEY CLUSTERED ([id] ASC)
                    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                          IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                          ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
CREATE TABLE [dbo].[Transactions]
(
    [id] [int] IDENTITY(1,1) NOT NULL,
    [widget_id] [int] NOT NULL,
    [transaction_data_1] [varchar](50) NOT NULL,

    PRIMARY KEY CLUSTERED ([id] ASC)
                WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                      IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                      ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO