INSERT 语句与 FOREIGN KEY 约束冲突 "FK__..."

The INSERT statement conflicted with the FOREIGN KEY constraint "FK__..."

我是 SQL 的新手,我遇到了一个我似乎找不到答案的问题。 我在 Stack Overflow 上发现了类似的问题,但我仍然看不到我应该在我的代码中更改什么以使其工作。

我有 4 个表的关系如下:

CREATE TABLE DeviceLocation (
    LocationId int not null identity(1,1) primary key,
    Latitude nvarchar(50) not null,
    Longitude nvarchar(50) not null
)

GO
CREATE TABLE TempHumidSensor (
    TempHumidSensorId int not null identity(1,1) primary key,   
    Humidity float not null,
    Temperature float not null
)

GO
CREATE TABLE LightSensor (
    LightSensorId int not null identity(1,1) primary key,
    LightPercentage int not null
)

GO
CREATE TABLE DeviceMessage (
    MessageId nvarchar(50) not null primary key,
    DeviceId nvarchar(20) not null,

    temperatureAlert nvarchar(20) not null,
    institutionClassName nvarchar(20) not null,
    institutionName nvarchar(20) not null,
    developerName nvarchar(20) not null,

    MessageTimestamp nvarchar(20) not null,
    TempSensorId int not null references TempHumidSensor(TempHumidSensorId),
    LightSensorId int not null references LightSensor(LightSensorId),
    DeviceLocationId int not null references DeviceLocation(LocationId)
)
GO

然后,我得到了三个返回标识值主键的过程 DeviceLocationTempHumidSensorLightSensor 在插入 DeviceMessage 之前,如下:

GetDeviceLocation

ALTER procedure [dbo].[GetDeviceLocation]
    @Latitude nvarchar(50), 
    @Longitude nvarchar(50)
as
begin
    if not exists (select 1 from DeviceLocation where Latitude = @Latitude and Longitude = @Longitude)
        insert into DeviceLocation output inserted.LocationId values (@Latitude, @Longitude)
    else
        select LocationId from DeviceLocation where Latitude = @Latitude and Longitude = @Longitude
end

GetLightSensor

ALTER procedure [dbo].[GetLightSensor]
    @LightPercentage int
as
begin
    if not exists (select 1 from LightSensor where LightPercentage = @LightPercentage)
        insert into LightSensor output inserted.LightSensorId values (@LightPercentage)
    else
        select LightSensorId from LightSensor where LightPercentage = @LightPercentage
end

GetTempHumidSensor

ALTER procedure [dbo].[GetTempHumidSensor]
    @Humidity float, 
    @Temperature float
as
begin
    if not exists (select 1 from TempHumidSensor where Humidity = @Humidity and Temperature = @Temperature)
        insert into TempHumidSensor output inserted.TempHumidSensorId values (@Humidity, @Temperature)
    else
        select TempHumidSensorId from TempHumidSensor where Humidity = @Humidity and Temperature = @Temperature
end

最后,还有 .NET 代码最终调用的 SaveSqlData 过程。

ALTER PROCEDURE [dbo].[SaveSqlData]
    @Latitude NVARCHAR(50),
    @Longitude NVARCHAR(50),
    @Humidity FLOAT,
    @Temperature FLOAT,
    @LightPercentage INT,
    @MessageTimestamp NVARCHAR(20),
    @MessageId NVARCHAR(50),
    @DeviceId NVARCHAR(20),
    @temperatureAlert NVARCHAR(20),
    @institutionClassName NVARCHAR(20),
    @institutionName NVARCHAR(20),
    @developerName NVARCHAR(20)

AS
BEGIN
    DECLARE @DeviceLocationId INT,
            @TempHumidSensorId INT,
            @LightSensorId INT

    EXEC @TempHumidSensorId = GetTempHumidSensor @Humidity = @Humidity, @Temperature = @Temperature
    EXEC @LightSensorId = GetLightSensor @LightPercentage = @LightPercentage
    EXEC @DeviceLocationId = GetDeviceLocation @Latitude = @Latitude, @Longitude = @Longitude


    INSERT INTO dbo.DeviceMessage(
        MessageId, 
        DeviceId, 
        temperatureAlert, 
        institutionClassName, 
        institutionName,
        developerName,
        MessageTimestamp,
        TempHumidSensorId,
        DeviceLocationId,
        LightSensorId
    ) 
    VALUES (
        @MessageId, 
        @DeviceId, 
        @temperatureAlert, 
        @institutionClassName, 
        @institutionName,
        @developerName,
        @MessageTimestamp,
        @TempHumidSensorId,
        @DeviceLocationId,
        @LightSensorId
    )
    END

我通常用这个片段测试这个程序:

exec dbo.SaveSqlData
    @Latitude = '55.5555',
    @Longitude = '66.6666',
    @Humidity = 41.2,
    @Temperature = 25.0,
    @LightPercentage = 91,
    @MessageTimestamp = 123123123,
    @temperatureAlert = 'false',
    @MessageId = 'sd344d3j-guid-mock-124-123',
    @DeviceId = 'device-name-from-device',
    @institutionClassName = 'class',
    @developerName = 'test',
    @institutionName = 'institution'

从 C# 和上面的测试调用调用此方法时显示的错误说:

(1 row affected)

(1 row affected)

(1 row affected)
Msg 547, Level 16, State 0, Procedure dbo.SaveSqlData, Line 27 [Batch Start Line 0]
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__DeviceMes__TempH__11D4A34F". The conflict occurred in database "telemetry-sqldb", table "dbo.TempHumidSensor", column 'TempHumidSensorId'.
The statement has been terminated.

我读到它与插入的顺序有关,但我不确定如何解决它或问题出在哪里。

当发生此错误时,我可以看到除了 DeviceMessage 之外的所有表都有插入。 非常感谢任何帮助。

您可以通过在 SaveSqlData 中放置诊断 SELECT @DeviceLocationId 等来查看问题 - 您将得到零。

您从 Get 存储过程中取回 ID 的方法不起作用。每个存储过程 SELECT 的 ID,但调用者(SaveSqlData 中的 EXEC)需要一个 return 值。

将您的 Get 存储过程更改为 RETURN id,例如:

ALTER procedure [dbo].[GetTempHumidSensor]
    @Humidity float, 
    @Temperature float
as
begin
    declare @id int

    if not exists (select 1 from TempHumidSensor where Humidity = @Humidity and Temperature = @Temperature)
        insert into TempHumidSensor values (@Humidity, @Temperature)

    select @id = TempHumidSensorId from TempHumidSensor where Humidity = @Humidity and Temperature = @Temperature

    return @id
end

请注意,您在 SaveSqlData 中也有错字,DeviceMessage 中的列名为 TempSensorId 而不是 TempHumidSensorId