如果值不在另一个 table 中,如何防止插入 SQL 服务器 table?

How to prevent an INSERT into a SQL Server table if a value is not in another table?

假设我有两个 SQL 服务器 table。一个包含“瞬态”数据 - 随着填充 table 的外部数据发生变化,记录被插入、更新和删除。

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

Table #1 - Widgets:

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

Table #2 - Transactions:

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

所以在上面的例子中,我需要确保 widget_iddbo.Widgets 中,否则会抛出错误。我不能使用从 TransactionsWidgets 的外键,因为 Transactions 记录是永久性的,当尝试删除 Widget 时,它会失败,因为它被外键引用了。

我可以使用 CHECK 约束在插入之前查找 Widgets table 中的值吗?或者也许是一个查找值并在不存在时抛出错误的触发器?我无法弄清楚两者如何工作以及可能的性能影响是什么。在这里寻找最佳实践。

提前致谢!

一个FOREIGN KEYCHECK CONSTRAINT的一种。我建议您在 INSERT 语句中添加一个 EXISTS 子句,这样您不想插入的行就不会插入。在伪 SQL 中将是:

INSERT INTO dbo.Transactions (widget_id,transaction_data_1)
SELECT widget_id,
       transaction_data_1
FROM (VALUES(...))V((widget_id,transaction_data_1)
WHERE EXISTS (SELECT 1
              FROM dbo.widgets w
              WHERE w.widget_id = v.widget_id);

如果您需要抛出错误,您可以使用如下所示的 TRIGGER,请注意,如果 table [=17] 中甚至不存在 1 个值=] 那么 entire INSERT 将失败:

CREATE TRIGGER dbo.trg_fk_TranasctionWidget
ON dbo.Transactions
AFTER INSERT
AS
IF EXISTS (SELECT 1
           FROM inserted i
               LEFT JOIN dbo.widgets w ON i.widget_id = w.widget_id
           WHERE w.widget_id IS NULL)
    --Change the error number to one suitable for your environment
    THROW 73246, N'The INSERT statement conflict with the trigger constraint trg_fk_TranasctionWidget. The conflict occured on the table "dbo.Transactions", column "widget_id".', 16;
GO

不过,就像@MartinSmith 看起来你真的应该看看级联。