Ignore Duplicate Values on Index prevents FOREIGN KEY constraint - sql-server

Due to some architectural reasons I have to ignore duplicate values on the index. It works perfectly well - except, when I am inserting wrong data. I am trying to insert value to the FK column that is supposed to throw:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__constrainName".
The conflict occurred in database, table "someTable", column 'FKColumn'.
Is there logic behind ignoring duplicate values that prevents insert statement from throwing this exception?

I assume you are talking about this kind of situation?
CREATE TABLE T2(T2_ID INT PRIMARY KEY)
INSERT INTO T2 VALUES (1),(2)
CREATE TABLE T1 (T1_ID INT, T2_ID INT REFERENCES T2)
CREATE UNIQUE CLUSTERED INDEX IX ON T1(T1_ID) WITH IGNORE_DUP_KEY
INSERT INTO T1 VALUES (1,2),(1,2),(2,3),(2,3)
/*FK Violation - No rows inserted*/
SELECT *
FROM T1
/*Duplicate key violation and potential FK Violation - one row inserted*/
INSERT INTO T1 VALUES (1,2),(1,2),(1,3),(1,3)
SELECT *
FROM T1
DROP TABLE T1
DROP TABLE T2
If a row is not inserted because it would cause a duplicate key violation then the FK constraint is not violated following the insert, hence no error.

Related

Insert/Update, ignore rows which would violate FK

If someone performs an update or insert on a table which has a foreign key to another, if a nonexistent value appears, an error is thrown. Is there an automated enough way to just ignore the faulty columns and continue with the others?
I can only think of an instead-of trigger, but it sounds messy.
You should check the rows in your INSERT query, by joining the source data with the referenced table.
For example, let's suppose that you have the following data in the SourceData table and you want to insert it in the Sales.CurrencyRate table in the AdventureWorks2019 database:
CREATE TABLE SourceData (
CurrencyRateDate datetime,
FromCurrencyCode char(3),
ToCurrencyCode char(3),
PRIMARY KEY (CurrencyRateDate, FromCurrencyCode, ToCurrencyCode),
Rate money NOT NULL
)
INSERT INTO SourceData (CurrencyRateDate, FromCurrencyCode, ToCurrencyCode, Rate) VALUES
('20200429','EUR','RON',4.8425),
('20200429','EUR','ROL',48425),
('20200430','EUR','RON',4.8421),
('20200430','EUR','ROL',48421)
INSERT INTO Sales.CurrencyRate (CurrencyRateDate, FromCurrencyCode, ToCurrencyCode, AverageRate, EndOfDayRate)
SELECT sd.CurrencyRateDate, sd.FromCurrencyCode, sd.ToCurrencyCode, sd.Rate, sd.Rate
FROM SourceData sd
If you simply run the INSERT statement mentioned above, you would get an error saying "The INSERT statement conflicted with the FOREIGN KEY constraint "FK_CurrencyRate_Currency_ToCurrencyCode". The conflict occurred in database "AdventureWorks2019", table "Sales.Currency", column 'CurrencyCode'.", because the currency "RON" is not present in the Sales.Currency table.
To avoid this error and insert only the data that has corresponding rows in the referenced table, you would simply use a JOIN for each FK, like this:
INSERT INTO Sales.CurrencyRate (CurrencyRateDate, FromCurrencyCode, ToCurrencyCode, AverageRate, EndOfDayRate)
SELECT sd.CurrencyRateDate, sd.FromCurrencyCode, sd.ToCurrencyCode, sd.Rate, sd.Rate
FROM SourceData sd
INNER JOIN Sales.Currency c1 ON c1.CurrencyCode=sd.FromCurrencyCode
INNER JOIN Sales.Currency c2 ON c2.CurrencyCode=sd.ToCurrencyCode

How to create connection between two tables in SQL Server 2008?

I have database that has Student table with information about each student in the system. Each record in that table has unique identifier that was created with NEWID() in SQL 2008. Then I have three other tables that use the same ID to link the student and the record. I'm wondering if I need to set any kind of property that will link these tables/records. Here is example of my Student table:
st_id -> Auto increment id
st_studentGUID -> Primary key
st_firstName
st_lastName
st_dob
st_gender
st_uid
st_udt
st_utime
And here is example of my other three tables:
Table 1 Table 2 Table 3
tb1_id -> auto increment tb2_id -> auto increment tb3_id -> auto increment
tb1_studentGUID tb2_studentGUID tb3_studentGUID
I have tried to create foreign key for each Table 1,2 and 3 on studentGUID but I got an error:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_Table1_Student". The conflict occurred in database "testDB", table "Student", column 'st_studentGUID'.
After I have done some research seems like this error occurred because Table 1 doesn't have all st_studentGUID. This make sense because student record might exist in Table 3 but not in Table 1. I'm wondering if there is any other sort of relation that I can set between the tables? Should I maybe use the Indexes on studentGUID fields? This is the reason why I'm asking this, in one of my update queries I use auto incremented id in where clause and for some reason I received an error that looks like this:
ErrorCode 1205
Message [Macromedia][SQLServer JDBC Driver][SQLServer]Transaction (Process ID 111) was deadlocked on lock | communication buffer resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
SQLState 40001
and error was pointing to the line that is end of the update query that looks like this:
<cfquery name="updateTable1" datasource="testDB">
UPDATE Table1
SET
tb1_testdt = <cfqueryparam value="#FORM.frm_testdt#" cfsqltype="cf_sql_date" maxlength="10" null="#yesNoFormat(!len(FORM.frmhs_testdtgr))#" />
FROM Table1 AS Table
LEFT OUTER JOIN studentLocked AS Locked
ON Locked.lk_studentGUID = Table.tb1_studentGUID
WHERE tb1_id = <cfqueryparam value="#FORM.frm_id#" cfsqltype="cf_sql_integer" />
AND lk_active = '1'
AND lk_staffID = <cfqueryparam value="#trim(appStaff)#" cfsqltype="cf_sql_char" maxlength="10" />
</cfquery>
Query above is checking if studentGUID exists in Lock table, reason why I'm doing this is because we do not want two different users updating the same record at the same time. Query updates single record and should be pretty fast. I'm confused whit the error message above deadlock victim. Is there something in my database design that is off or my update query is causing this error? I couldn't find anything on the web that could help me fix this issue. if anyone has experience with this kind of problem please let me know.
If all StudentGUIDs exist in the Student table, then the correct design is to have the StudentGUID in Table1, Table2 and Table3 be a Foreign Key to the Student table.
Now that you've sorted out your foreign key issue with the missing record from Student, try setting up your FKs on all of your tables, then re-try your update query.
If the deadlock issue persists and is reproducible, submit a new question for that, including the schema for the table you're updating and the values you're trying to pass.
Here's a script that demonstrates you can create the relationships you described provided all the keys are present in the students table:
CREATE TABLE students (st_id AS NEWID(),
st_studentGUID UNIQUEIDENTIFIER PRIMARY KEY)
INSERT INTO students (st_studentGUID) VALUES ('3B9F59DD-BF0A-4A09-BF4E-A396E2978B24')
INSERT INTO students (st_studentGUID) VALUES ('7CC5FF67-DAB8-426A-B9F7-E9F041718B6B')
INSERT INTO students (st_studentGUID) VALUES ('84B80D3E-44C4-4291-857D-B6CA6552369D')
CREATE TABLE t1 (tb1_id AS NEWID(), tb1_studentGUID UNIQUEIDENTIFIER)
ALTER TABLE t1
ADD CONSTRAINT FK_t1_tbl_studentGUID FOREIGN KEY (tb1_studentGUID) REFERENCES students(st_studentGUID)
INSERT INTO t1 (tb1_studentGUID) VALUES ('3B9F59DD-BF0A-4A09-BF4E-A396E2978B24')
CREATE TABLE t2 (tb2_id AS NEWID(), tb2_studentGUID UNIQUEIDENTIFIER)
ALTER TABLE t2
ADD CONSTRAINT FK_t2_tbl_studentGUID FOREIGN KEY (tb2_studentGUID) REFERENCES students(st_studentGUID)
INSERT INTO t2 (tb2_studentGUID) VALUES ('7CC5FF67-DAB8-426A-B9F7-E9F041718B6B')
CREATE TABLE t3 (tb3_id AS NEWID(), tb3_studentGUID UNIQUEIDENTIFIER)
ALTER TABLE t3
ADD CONSTRAINT FK_t3_tbl_studentGUID FOREIGN KEY (tb3_studentGUID) REFERENCES students(st_studentGUID)
INSERT INTO t3 (tb3_studentGUID) VALUES ('84B80D3E-44C4-4291-857D-B6CA6552369D')
Now create a 4th table, add a UUID that isn't in the students table, and try to create the foreign key constraint:
CREATE TABLE t4 (tb4_id AS NEWID(), tb4_studentGUID UNIQUEIDENTIFIER)
INSERT INTO t4 (tb4_studentGUID) VALUES ('897925F1-BE92-44EB-82C3-88E1C33C7792')
ALTER TABLE t4
ADD CONSTRAINT FK_t4_tbl_studentGUID FOREIGN KEY (tb4_studentGUID) REFERENCES students(st_studentGUID)
Which reproduces your error message:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_t4_tbl_studentGUID". The conflict occurred in database "IconERP", table "dbo.students", column 'st_studentGUID'.

How to insert data with the cross-referenced tables?

I have two tables. The table structure is given below.
CREATE TABLE t1
(
col1 int PRIMARY KEY,
col2 int REFERENCES t2(col4)
)
And
CREATE TABLE t2
(
col3 int PRIMARY KEY,
col4 int REFERENCES t1(col1)
)
Now how do I populate the tables using INSERT statement. I can do it by inserting a NULL value in the FOREIGN KEY COLUMN and then UPDATE that column. But I don't want to use the UPDATE statement. I want to do it using a INSERT statement.
How should I do it?
I sense a bad design decision here. If update is not an option, then disabling the constraint, inserting data and then re-enabling the constraint can be considered, but that is also an inherently bad approach, as the very purpose of enforcing those constraints in the first place is defeated.
Anyway, here is how:
ALTER TABLE t1 NOCHECK CONSTRAINT <YourFKConstraint>
ALTER TABLE t2 NOCHECK CONSTRAINT <YourFKConstraint>
GO
INSERT INTO t1
VALUES (1,1)
GO
INSERT INTO t2
VALUES (1,1)
GO
ALTER TABLE t1 CHECK CONSTRAINT <YourFKConstraint>
ALTER TABLE t2 CHECK CONSTRAINT <YourFKConstraint>
Please be warned that this approach will allow you to enter data that violates the constraint. Redesign would be the best option.

SQL Constraint-Insert Fails

I have two table table1 and table2. I have a record in table1. I want to insert record into table2. but it comes up with the following Exception.
Msg 547, Level 16, State 0, Line 2
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Table2_<Column3>". The conflict occurred in database "<databaseName>", table "table1", column 'Id'.
The constraint on the table2 is like this.
ALTER TABLE [dbo].[table2] ADD CONSTRAINT [DF__table2__name__0B91BA14] DEFAULT ((0)) FOR [column4]
The error shows that you also have a foreign key constraint and you are trying to insert a row into a child table that doesn't have corresponding record in master
The exception message is telling you which constraint is causing the issue. It's against Column3 (at least that's what the name suggests) and is a foreign key constraint against table1.
You're not showing any sample SQL but it would appear you're trying to insert data in to table2 where the foreign key value specified for Column3 does not exist in table1.
Your Comment helped me.
I have used this Query to insert data into the new database from the old databse.
INSERT INTO Database.[dbo].[Table2] ([colmn1]
,[colmn2]
,[colmn3]
,[columns4]
)
SELECT [colmn1]
,[colmn2]
,[colmn3]
,[columns4]
FROM [OtherDatabase].[dbo].[Table2]
But there is a constarint on colum3 which is foreign key on Table1.
I have changed the colmn3 of table1 to same Guid as otherDatabase Guid and it works.
Thanks All

Fixing broken foreign keys with ALTER TABLE ... WITH CHECK CHECK CONSTRAINT

I have a broken foreign key in SQL Server 2005. Here is a reproduction:
CREATE TABLE t2(i2 BIGINT NOT NULL PRIMARY KEY)
CREATE TABLE t1(i1 BIGINT NOT NULL PRIMARY KEY)
ALTER TABLE t1 ADD CONSTRAINT fk FOREIGN KEY (i1) REFERENCES t2 (i2)
ALTER TABLE t1 NOCHECK CONSTRAINT fk
INSERT INTO t1 (i1) VALUES (0)
If I subsequently run:
ALTER TABLE t1 WITH CHECK CHECK CONSTRAINT fk
I get the error:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "fk". The conflict occurred in database "broken-fk", table "dbo.t2", column 'i2'.
I can fix this manually:
DELETE FROM t1 WHERE NOT EXISTS (SELECT 1 FROM t2 WHERE t2.i2 = t1.i1)
ALTER TABLE t1 WITH CHECK CHECK CONSTRAINT fk
but I'd prefer to do it in one step, as each presumably needs a table scan and the table is tens of gigabytes in size.
Is it possible to get the ALTER TABLE to fix the error (by dropping rows) rather than exiting with an error?
Thanks.
Is it possible to get the ALTER TABLE to fix the error
(by dropping rows) rather than exiting with an error?
The long and short - no.
Do it in two steps as you are familiar with.
You could stop at
ALTER TABLE t1 CHECK CONSTRAINT fk
which turns it on for new records but leaves the existing data alone?

Resources