SQL add Foreign key constraint with check - sql

I have the following query which is adding contraint.
but in order to add, i want to check if this key has already been used or not?
ALTER TABLE HL7_MessageHierarchy
ADD CONSTRAINT fk_vMessageType FOREIGN KEY (vMessageType)
REFERENCES HL7_MessageType(vMessageType);
for example. if i have to add a column, i can easily check if the table exists in sysobjects and its respective column exists in syscolumns.
Is it possible to use the query multiple times without GO and without making any error indeed? if yes then how ???
[EDIT]
I don't know why my browser not allowing me to add comments so i am adding to Edit.
I want to check if there exists any foreign key with same name. so if there is no data even then the query can make problem because the key may already be existing. I want to run the above script clean (ofcourse resident data does matter but that is perhaps a straight forward check?)
[EDIT]
my bad, i must have known that version is important... I believe its 2005... (will love to know if someone can tell for other versions too)

I assume you mean
check the HL7_MessageHierarchy for values not inHL7_MessageType"
So, a query like this will tell you
SELECT *
FROM HL7_MessageHierarchy H
WHERE NOT EXISTS (SELECT *
FROM HL7_MessageType T
WHERE H.vMessageType = T.vMessageType)
Also, I'd recommend using WITH CHECK too
ALTER TABLE HL7_MessageHierarchy WITH CHECK ADD
CONSTRAINT fk_vMessageType FOREIGN KEY (vMessageType)
REFERENCES HL7_MessageType(vMessageType);

In SQL 2005, the recommended way of checking for the existence of objects is Catalog Views. The one you want is sys.foreign_keys:
IF NOT EXISTS ( SELECT * FROM sys.foreign_keys
WHERE name = 'fk_vMessageType' )
BEGIN
EXEC ('
ALTER TABLE HL7_MessageHierarchy
ADD CONSTRAINT fk_vMessageType FOREIGN KEY (vMessageType)
REFERENCES HL7_MessageType(vMessageType)
')
END
I have wrapped the creation in EXEC to avoid confusing the parser.

Related

Inserting new record and skip if foreign key conflict in sql server 2008 R2

I have the problem similar to this one SQL Server foreign key conflict in a multi values statement? However, in sql server 2008.
While I am reading data from csv file, there is some id already not exist in parent and thus return this error:
INSERT statement conflicted with the FOREIGN KEY constraint
May I know if there is a way similar to MySQL insert ignore. Such that I can simply skip the problematic data.
I accept that if there is no method other than creating a stored procedure with a new temp table (insert into a table without foreign key first, and then re-insert with where foreign_id exists in (select id from parent)).
As I really cannot find any in documentation, asking for ensuring I didn't miss anything.
One general solution which comes to mind would be to temporarily turn off the foreign key constraints, and do the insert. Then, afterwards, you may run a cleanup script/query to remove or rectify child records which are pointing to parents which do not exist. Once your data is in good shape, then turn on the foreign key constraints again.
Read How can foreign key constraints be temporarily disabled using T-SQL? to learn how to disable/enable a foreign key constraint for a single table:
ALTER TABLE MyTable NOCHECK CONSTRAINT MyConstraint -- disable
ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT MyConstraint -- enable

Create field constraint based on another table field in LibreOffice Base

I have 3 tables, "Courses"(id, start_date), "Subscriptions"(id, assistant_id, course_id, date) and "Assistants"(id, registration_date).
Subscriptions reference Courses and Assistants with foreign keys as you see.
I need to add CHECK constraint that will prevent to create Subscription record if referenced Courses.start_date is older than referenced Assistants.registration_date. Is there a way to do this in Libre Base?
Table organization could not be changed.
Such a CHECK constraint cannot be created with the default engine. From the HSQLDB 1.8 documentation:
ALTER TABLE <tablename> ADD [CONSTRAINT <constraintname>]
CHECK (<search condition>);
Adds a check constraint to the table. In the current version, a check constraint can reference only the row
being inserted or updated.
This means that commands like the following from TestSelfCheckConstraints.txt produce an error:
/*e*/CREATE TABLE TC6(A CHAR, B CHAR, C CHAR, D INT, CHECK(A IN (SELECT A FROM
TC5)));
So, to perform such a check, you will have to verify it ahead of time (or afterwards) using a query. This could be done for a form by adding a macro in the Events tab. See this post for ideas: https://forum.openoffice.org/en/forum/viewtopic.php?f=20&t=21414.
The default engine is rather old, so for such complex requirements it may be better to set up LibreOffice Base to use a different database engine. For example using MySQL, it is possible to set up a stored procedure trigger to do this kind of checking. See CHECK constraint in MySQL is not working.

What is the effect (or purpose) of a foreign key column referencing itself?

During a database migration, I've run across a database table constraint of the form:
ALTER TABLE [dbo].[myTable]
ADD CONSTRAINT [someName] FOREIGN KEY ([id]) REFERENCES [dbo].[myTable] ([id])
ON DELETE NO ACTION
ON UPDATE NO ACTION
Why would one do this? This was originally done on a Sybase database, and we are converting to SQL Server 2008 R2.
UPDATE: Yes, the foreign key constraint is a field referencing the same table AND SAME FIELD.
I ran this query on the source Sybase database and found 42 of these crazy keys defined, so it doesn't seem like a typo.
SELECT sr.constrid as [Constraint ID],
so.name as [Table],
sc.name as [Column]
FROM sysreferences sr
INNER JOIN sysobjects so ON (so.id = sr.tableid)
INNER JOIN syscolumns sc ON (sc.id = sr.tableid AND sc.colid = sr.fokey1)
WHERE sr.tableid = sr.reftabid
AND sr.fokey1 = sr.refkey1
AND sr.fokey2 = 0
AND sr.refkey2 = 0
I believe that hierarchies are the standard examples you'll find in books whenever you use foreign keys for the same table, such as:
create table Employees (
EmployeeID int identity primary key,
EmployeeName varchar(50),
ManagerID int
Foreign key (managerID) references Employees(EmployeeID)
)
What you posted looks like a wrong application of this hierarchy relation in the same table. I'm not entirely sure why you'd ever wanna do that.
Hope this helped =)
Surprise! This totally works:
create table crazy (
ID int primary key references crazy (ID) -- This runs
);
insert into crazy select 1; -- So does this
select * from crazy; -- Returns 1
truncate table crazy; -- Works just fine
I can only think that this would have been a mistake (Typo? Dragging a column onto itself in a diagram?) or used to fool another system (ORM?) into some particular behavior. I will be very curious to see if someone comes up with a legit reason.
UPDATE: As cleverly suggested by #8kb, this could have been an attempt to prevent truncation, but we can see from my example that even truncation works just fine.
I guess it's a bug in database model.
It's really weird. I can't imagine what usefull purpose is this construction.
The only way how to insert data is without checking reference integrity. It means with explicitly disabled references or with some kind of bulk insert and so on.
The effect of a foreign key column referencing itself seems to be nothing. It is still an outstanding question as to why a database engine would let you do such a useless thing.
However, I believe the reason someone would build a foreign key like this is laziness / carelessness. I found out that in SQL Server Management Studio, if you build a foreign key using the GUI (instead of writing it out in T-SQL), the initial behavior of SSMS is to create foreign key exactly like in this question:
Expand any table of a database in the Object Explorer pane. We will call this table TableA.
Rt-click on Keys under the TableA node and select New Foreign Key... This will open the Modify table pane and the Foreign Key Relationships dialog.
Changing nothing, simply click the Close button on the Foreign Key Relationships dialog. "Oops, I didn't mean to try to add a foreign key."
Closing the dialog still generated a foreign key with the name FK_TableA_TableA and picked the primary key column as both the base and reference column.
With the Modify table pane still open (which it still is after closing the Foreign Key Relationships dialog), close it. It has changes (the new foreign key you just made). Save these changes.
A new foreign key now exists in the database for TableA, with the primary key column referencing itself.

How to ALTER a table on iSeries that has constraints? Getting "*FILE in use." error

I have a table on a iSeries(IBM-i/AS400) which has some constraints. The table is created with SQL like so, with a handful of foreign keys linking from other tables to this table (actual SQL has been a bit obfuscated here):
CREATE TABLE ABCLIB.ABCDE (
DEIDN INTEGER NOT NULL WITH DEFAULT,
DETTL VARGRAPHIC (50) ALLOCATE(25),
DETYP CHAR (1) NOT NULL WITH DEFAULT);
ALTER TABLE ABCLIB.ABCDE ADD PRIMARY KEY (DEIDN);
ALTER TABLE ABCLIB.ABCFG ADD FOREIGN KEY (FGDEK)
REFERENCES ABCLIB.ABCDE (DEIDN)
ON DELETE RESTRICT ON UPDATE RESTRICT;
ALTER TABLE ABCLIB.ABCHI ADD FOREIGN KEY (HIDEK)
REFERENCES ABCLIB.ABCDE (DEIDN)
ON DELETE RESTRICT ON UPDATE RESTRICT;
Now, much later, I will need to alter that table to add a field:
ALTER TABLE ABCLIB.ABCDE ADD COLUMN DEICN VARGRAPHIC (100) ALLOCATE(50)
Which results in this message:
Row or object ABCDE in ABCLIB type *FILE in use.
I have checked and there are definitely no object locks on this table at this time. When I check the joblog, I see this:
Constraint cannot be removed from file Q_AT000000.
Constraint(s) not removed from file Q_AT000000.
File ABCDE in ABCLIB not changed.
Row or object ABCDE in ABCLIB type *FILE in use.
Now, I could of course remove and re-add the constraints in question, but I feel like this should not be necessary. The column I am adding has nothing to do with the constraints. I believe this probably is a result of the fact that in fact OS400 (i5/OS) is not really altering the existing table but instead is creating a new table and copying data in, and that is probably where the pain comes in.
But is there a way to possibly suspend the keys and then resume them after the alter?
(Answers that do not involve doing this with SQL or suggest creating the table differently in the first place are not helpful as they are not applicable here...)
The answer is: I missed the fact that there was a lock on one of the tables that had a foreign key pointing to that table. Or, put more bluntly: I am an idiot!
Does Enabling or disabling referential constraints help?

TRUNCATE TABLES with CONSTRAINTS

Is there a way to truncate tables with constraints ?
I tried to DEACTIvATE with this:
DECLARE #SQLtxt varchar(max)
SET #SQLtxt = '-- DESACTIVER LES CONTRAINTES' + CHAR(10)
SELECT #SQLtxt = #SQLtxt + 'ALTER TABLE [' + name + '] NOCHECK CONSTRAINT ALL;' FROM sys.tables
PRINT #SQLtxt
Of course, it didn't worked. I have to drop the constraint then recreate them ! The only way I could make it work is by extracting the script to drop and recreate the contraint.
Is there another way ? BTW I don't want to delete because it would use the Transaction Log.
Here is a script that may help you get going scripting out FK's. Script out your foreign keys.
I use a modified version to dump the constraint definitions into a temp table, then do the TRUNCATE magic and then recreate the constraints from the temp table. However, this is only for my own convenience when restoring the production database onto a non-production environment to get rid of most of the data. Not sure, I would use it in a production scenario though. I would rather prefer deleting in small batches knowing that everything is fully logged.
Btw, womb's reference to the SQL Server 2000 Books Online is a bit misleading. TRUNCATE TABLE has always been a minimally logged operation.
TRUNCATE TABLE removes the data by deallocating the data pages used to store the table's data, and only the page deallocations are recorded in the transaction log.
This is has specified more precisely in later versions of Books Online.
The TRUNCATE command will not work on tables with FK references. Straight from the documentation:
You cannot use TRUNCATE TABLE on a
table referenced by a FOREIGN KEY
constraint; instead, use DELETE
statement without a WHERE clause.
Because TRUNCATE TABLE is not logged,
it cannot activate a trigger.
You sort of answered the question yourself - if there's a foreign key referencing your table, SQL Server needs that information in the transaction log. Since TRUNCATE TABLE effectively bypasses the log, it's not allowed on tables referenced by foreign keys.
You'll either have to DROP the foreign key constraint, or use a DELETE statement.
It's only referencing (eg the REFERENCES bit) foreign keys you need to drop.
This should make it easier...