The INSERT statement conflicted with the FOREIGN KEY constraint problem - sql

I have the script below, which gives me an error:
"The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.PlanShiftAssignments_dbo.User_UserId". The conflict occurred in database "SWS", table "dbo.User", column 'Id'.
The statement has been terminated."
As you can see, in WHERE clause I check if UserId exists in dbo.User. What are the other possible reasons of the error?
UPDATED: I am also want to know what row from select statement causes the error. Any advices on debugging this query will be appreciated. I am using MS SQL Server Management Studio.
CREATE TABLE [dbo].[PlanShiftAssignments] (
[PlanShiftId] [uniqueidentifier] NOT NULL,
[Status] [int] NOT NULL,
[UserId] [int],
CONSTRAINT [PK_dbo.PlanShiftAssignments] PRIMARY KEY ([PlanShiftId])
)
CREATE INDEX [IX_PlanShiftId] ON [dbo].[PlanShiftAssignments]([PlanShiftId])
CREATE INDEX [IX_UserId] ON [dbo].[PlanShiftAssignments]([UserId])
ALTER TABLE [dbo].[PlanShiftAssignments] ADD CONSTRAINT [FK_dbo.PlanShiftAssignments_dbo.PlanShifts_PlanShiftId] FOREIGN KEY ([PlanShiftId]) REFERENCES [dbo].[PlanShifts] ([Id])
ALTER TABLE [dbo].[PlanShiftAssignments] ADD CONSTRAINT [FK_dbo.PlanShiftAssignments_dbo.User_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id])
insert into dbo.PlanShiftAssignments
select ps.Id as PlanShiftId, ISNULL(ps.AssigneeId, psi.UserId) as UserId, ISNULL(psi.[Status], 1) as [Status] from dbo.PlanShifts ps
left join
dbo.PlanShiftInvitations psi
on ps.Id = psi.PlanShiftId
where (psi.UserId is not null and psi.UserId IN (select Id from dbo.[User]))
or (ps.AssigneeId is not null and ps.AssigneeId IN (select Id from dbo.[User]))

Make sure that you always include the target's column list on each INSERT statement.
insert into dbo.PlanShiftAssignments (
PlanShiftId,
UserId,
Status)
SELECT
ps.Id as PlanShiftId,
ISNULL(ps.AssigneeId, psi.UserId) as UserId,
ISNULL(psi.[Status], 1) as [Status]
...
Your table is created with the order PlanShiftId, Status, UserId and the column order from your current SELECT is PlanShiftId, UserId, Status, hence the confusion.

You have a strange data model, if UserId and AssigneeId do not already refer to User in the underlying tables.
In any case, your where clause is
where (psi.UserId is not null and psi.UserId IN (select Id from dbo.[User])) or
(ps.AssigneeId is not null and ps.AssigneeId IN (select Id from dbo.[User]))
This leaves open the possibility that psi.UserId matches but ps.AssigneeId does not.
To ensure that the logic matches, use the same expression as in the select:
where coalesce(ps.AssigneeId, psi.UserId) in (select Id from dbo.[User])

Could it be for the fact you've specified an OR in your WHERE clause, therefore either the AssigneeId or UserId is in the User table but not the other and therefore invalidates the FK constraint.

Related

Check for uniqueness of column in postgres table

I need to ensure that the values in a column from a table are unique as part of a larger process.
I'm aware of the UNIQUE constraint, but I'm wondering if there is a better way to do the check.
I'm running the queries using psycopg2 so adding that tag on the off chance there's something in there that can help with this.
If the column is unique I can add a constraint. If the column is not unique adding the constraint will return an error.
If there is already a constraint of the same name a useful error is returned. in this case would prefer to just check for the existing constraint.
If the column is the primary key, the unique constraint can be added without error but in this case it would be preferable to just recognize that the column must be unique based on the primary key.
Code examples of this below.
DROP TABLE IF EXISTS unique_test;
CREATE TABLE unique_test (
pkey INT PRIMARY KEY,
unique_yes CHAR(1),
unique_no CHAR(1)
);
INSERT INTO unique_test (pkey, unique_yes, unique_no)
VALUES(1, 'a', 'a'),
(2, 'b', 'a');
CREATE UNIQUE INDEX CONCURRENTLY u_test_1 ON unique_test (unique_yes);
ALTER TABLE unique_test
ADD CONSTRAINT unique_target_1
UNIQUE USING INDEX u_test_1;
-- the above runs no problem
-- check what happens when column is not unique
CREATE UNIQUE INDEX CONCURRENTLY u_test_2 ON unique_test (unique_no);
ALTER TABLE unique_test
ADD CONSTRAINT unique_target_2
UNIQUE USING INDEX u_test_2;
-- returns:
-- SQL Error [23505]: ERROR: could not create unique index "u_test_2"
-- Detail: Key (unique_no)=(a) is duplicated.
CREATE UNIQUE INDEX CONCURRENTLY u_test_1 ON unique_test (unique_yes);
ALTER TABLE unique_test
ADD CONSTRAINT unique_target_1
UNIQUE USING INDEX u_test_1;
-- returns
-- SQL Error [42P07]: ERROR: relation "unique_target_1" already exists
-- test what happens if adding constrint to primary key column
CREATE UNIQUE INDEX CONCURRENTLY u_test_pkey ON unique_test (pkey);
ALTER TABLE unique_test
ADD CONSTRAINT unique_target_pkey
UNIQUE USING INDEX u_test_pkey;
-- this runs no problem but is inefficient.
If all you want to do is verify that values are unique, then use a query:
select unique_no, count(*)
from unique_test
group by unique_no
having count(*) > 1;
If it needs to be boolean output:
select not exists (
select unique_no, count(*)
from unique_test
group by unique_no
having count(*) > 1
);
If you just want a flag, you can use:
select count(*) <> count(distinct uniq_no) as duplicate_flag
from unique_test;
DELETE FROM
zoo x
USING zoo y
WHERE
x.animal_id < y.animal_id
AND x.animal = y.animal;
I think this is simpler, https://kb.objectrocket.com/postgresql/delete-duplicate-rows-in-postgresql-762 for reference

SQL set check constraint

I have a problem with setting check constrain. I have table Policy where primary key is set on (Policy_id, History_id) + additional columns and table Report which have Policy_id and some additional columns.
How can I set check constraint statement on Report table to check if policy_id exists in Policy table?
I cannot use foreign key constrain because Report do not have history_id column
Report cannot contain record with Policy_id if it do not exists in Policy table and hence, cannot perform insert into Report
If the Policy_id and History_id are a composite primary key then the foreign key on the referencing table must also hold the both columns.
If you really need to check just for one of them (the policy_id) I guess you'd have to do it manually which is not a good idea.
It would be better if the Report table would have 2 foreign keys and both the policy_id and history_id would be a single primary keys.
You could create a separate table just for the purposes of this foreign key constraint and then use triggers to maintain this data:
CREATE TABLE ExistingPolicies (
PolicyID int not null,
PolicyCount int not null,
constraint PK_ExistingPolicies PRIMARY KEY (PolicyID)
)
And then the triggers:
CREATE TRIGGER T_Policy_I
on Policy
instead of insert
as
;With totals as (
select PolicyID,COUNT(*) as cnt from inserted
group by PolicyID
)
merge into ExistingPolicies t
using totals s
on
t.PolicyID = s.PolicyID
when matched then update set PolicyCount = PolicyCount + s.cnt
when not matched then insert (PolicyID,PolicyCount) values (s.PolicyID,s.cnt);
go
CREATE TRIGGER T_Policy_D
on Policy
instead of delete
as
;With totals as (
select PolicyID,COUNT(*) as cnt from deleted
group by PolicyID
)
merge into ExistingPolicies t
using totals s
on
t.PolicyID = s.PolicyID
when matched and t.PolicyCount = s.cnt then delete
when matched then update set PolicyCount = PolicyCount - s.cnt;
go
CREATE TRIGGER T_Policy_U
on Policy
instead of update
as
;With totals as (
select PolicyID,SUM(cnt) as cnt
from
(select PolicyID,1 as cnt from inserted
union all
select PolicyID,-1 as cnt from deleted
) t
group by PolicyID
)
merge into ExistingPolicies t
using totals s
on
t.PolicyID = s.PolicyID
when matched and t.PolicyCount = -s.cnt then delete
when matched then update set PolicyCount = PolicyCount + s.cnt
when not matched then insert (PolicyID,PolicyCount) values (s.PolicyID,s.cnt);
go
(Code not tested but should be close to correct)
I think using a check constraint is a fine idea here.
Write a function that accepts Policy_id as a parameter, and does a query to check if the policy exists in the Policy table, and returns a simple 1 (exists) or 0 (does not exist).
Then set your check constraint on your Report Table to dbo.MyFunction(Policy_Id)=1
That's it.

Primary key consists of a foreign key and a identity and should reset identity under a condition

create table Linq_TB
{
url_id int NOTNULL,
Pg_Name nvarchar(50) NOTNULL,
URL nvarchar(50) NUTNULL,
CONSTRAINT Linq_id PRIMARY KEY (url_id,DBCC Checkident(Linq_TB,RESEED,0) case url_id not in(select URL_Id from URL_TB ))
}
I want to make a table which it's primary key is Linq_id and gets it's value from both the url_id and identity with start from 1 and increments 1 by 1. url_id is a foreign key. For example if url_id is 1, linq_id's will be 11, 12, 13,... and I also want to reset linq_id identity when the url_id changes.
What should the query be? The query above doesn't work, why?
Thanks in advance
Well, a constraint contains conditions and not code to be executed. You should consider using a stored procedure for your task and also a homegrown method of assigning IDs.
However, it is not a common practice to have your primary keys 'pretty' or formatted, as there is no real benefit (except maybe for debugging purposes maybe).
I do not recommend executing DBCC whenever your url_ID changes. This has a great negative impact on performance.
Why don't you leave the IDs like they are?
You can do this with the following table and trigger definitions:
CREATE TABLE Linq_TB
(
url_id INT NOT NULL,
Linq_id INT NOT NULL,
Pg_Name NVARCHAR(50) NOT NULL,
URL NVARCHAR(50) NOT NULL,
CONSTRAINT PK_Link_TB PRIMARY KEY (url_id, Linq_id),
CONSTRAINT FK_URL_TB_URL_ID FOREIGN KEY (url_id) REFERENCES URL_TB (url_id)
)
GO
CREATE TRIGGER tr_Linq_TB_InsertUpdate
ON Linq_TB
INSTEAD OF INSERT
AS
INSERT INTO Linq_TB
SELECT i.url_id,
ISNULL(tb.Linq_id, 0)
+ row_number() over (partition by i.url_id order by (select 1)),
i.Pg_Name, i.URL
FROM inserted i
LEFT OUTER JOIN
(
SELECT url_id, MAX(Linq_ID) Linq_id
FROM Linq_TB
GROUP BY url_id
) tb ON i.url_id = tb.url_id
GO
The CREATE TABLE defines your columns and constraints. And, the trigger creates the logic to generate a sequence value in your Linq_id column for each url_id.
Note that the logic in the trigger is not complete. A couple of issues are not addressed: 1) If the url_id changes for a row, the trigger doesn't update the Link_id, and 2) deleting rows will lead to gaps in the Linq_TB column sequence.

Creating an insert query (error on foreign key constraint)

I want to move data from one database's table to another database's table. I am getting a foreign key error. How can I insert all the data which is valid except those rows who don't have a foreign key?
My query is :
SET IDENTITY_INSERT City ON
INSERT INTO City ([cityid],[city],[country],[state],[cityinfo]
,[enabled],[countryid],[citycode],[stateid],[latitude],[longitude])
SELECT [cityid],[city],[country],[state],[cityinfo]
,[enabled],[countryid],[citycode],[stateid],[latitude],[longitude]
FROM TD.DBo.City
getting this error:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__city__countryid__3E52440B". The conflict occurred in database "schoolHigher", table "dbo.country", column 'countryId'.
INNER JOIN the other database's table with the country table. Only those records with an existing country will get selected.
Note: you should check that the corresponding countryid's in both databases match.
SET IDENTITY_INSERT City ON
INSERT INTO City (
[cityid]
,[city]
,[country]
,[state]
,[cityinfo]
,[enabled]
,[countryid]
,[citycode]
,[stateid]
,[latitude]
,[longitude])
SELECT ct.[cityid]
,ct.[city]
,ct.[country]
,ct.[state]
,ct.[cityinfo]
,ct.[enabled]
,ct.[countryid]
,ct.[citycode]
,ct.[stateid]
,ct.[latitude]
,ct.[longitude]
FROM TD.DBo.City ct
INNER JOIN dbo.Country cnt ON cnt.CountryID = ct.CountryID

SQL Server 2005: Nullable Foreign Key Constraint

I have a foreign key constraint between tables Sessions and Users. Specifically, Sessions.UID = Users.ID. Sometimes, I want Sessions.UID to be null. Can this be allowed? Any time I try to do this, I get an FK Constraint Violation.
Specifically, I'm inserting a row into Sessions via LINQ. I set the Session.User = null; and I get this error:
An attempt was made to remove a relationship between a User and a Session. However, one of the relationship's foreign keys (Session.UID) cannot be set to null.
However, when I remove the line that nulls the User property, I get this error on my SubmitChanges line:
Value cannot be null.
Parameter name: cons
None of my tables have a field called 'cons', nor is it in my 5,500-line DataContext.designer.cs file, nor is it in the QuickWatch for any of the related objects, so I have no idea what 'cons' is.
In the Database, Session.UID is a nullable int field and User.ID is a non-nullable int. I want to record sessions that may or may not have a UID, and I'd rather do it without disabling constraint on that FK relationship. Is there a way to do this?
I seemed to remember creating a nullable FK before, so I whipped up a quick test. As you can see below, it is definitely doable (tested on MSSQL 2005).
Script the relevant parts of your tables and constraints and post them so we can troubleshoot further.
CREATE DATABASE [NullableFKTest]
GO
USE [NullableFKTest]
GO
CREATE TABLE OneTable
(
OneId [int] NOT NULL,
CONSTRAINT [PK_OneTable] PRIMARY KEY CLUSTERED
(
[OneId] ASC
)
)
CREATE TABLE ManyTable (ManyId [int] IDENTITY(1,1) NOT NULL, OneId [int] NULL)
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ManyTable_OneTable]') AND parent_object_id = OBJECT_ID(N'[dbo].[ManyTable]') )
ALTER TABLE [dbo].[ManyTable] WITH CHECK ADD CONSTRAINT [FK_ManyTable_OneTable] FOREIGN KEY([OneId])
REFERENCES [dbo].[OneTable] ([OneId])
GO
--let's get a value in here
insert into OneTable(OneId) values(1)
select* from OneTable
--let's try creating a valid relationship to the FK table OneTable
insert into ManyTable(OneId) values (1) --fine
--now, let's try NULL
insert into ManyTable(OneId) values (NULL) --also fine
--how about a non-existent OneTable entry?
insert into ManyTable(OneId) values (5) --BOOM! - FK violation
select* from ManyTable
--1, 1
--2, NULL
--cleanup
ALTER TABLE ManyTable DROP CONSTRAINT FK_ManyTable_OneTable
GO
drop TABLE OneTable
GO
drop TABLE ManyTable
GO
USE [Master]
GO
DROP DATABASE NullableFKTest