Оператор INSERT конфликтовал с ограничением FOREIGN KEY "FK __..." - PullRequest
1 голос
/ 27 февраля 2020

Я очень новичок с SQL, и я борюсь с проблемой, на которую не могу найти ответ. Я нашел подобные вопросы здесь о переполнении стека, но я все еще не вижу, что я должен изменить в своем коде, чтобы заставить его работать.

У меня есть 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

Затем у меня есть три процедуры, которые возвращают первичный ключ значения идентификатора для DeviceLocation , TempHumidSensor , LightSensor перед вставкой в ​​ 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

Наконец, есть процедура SaveSqlData , которая вызывается кодом. NET в конце.

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#, так и при выполнении указанного выше теста: 1041 *

(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. Любая помощь очень ценится.

1 Ответ

3 голосов
/ 27 февраля 2020

Вы можете увидеть проблему, поставив диагноз c SELECT @DeviceLocationId et c в SaveSqlData - вы получите нули.

То, как вы получаете идентификаторы от вашего Get sprocs не работает. Каждый spro c SELECT s является идентификатором, но вызывающая сторона (EXEC in SaveSqlData) ожидает возвращаемого значения.

Измените Get sprocs на 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...