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
然后,我得到了三个返回标识值主键的过程
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
最后,还有 .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
。
我是 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
然后,我得到了三个返回标识值主键的过程 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
最后,还有 .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
。