I'm new to SQL and try to get some handy knowledge from the book "SQL for Microsoft Access 2nd Edition" published in 2008.
In chapter 3, keyword ON UPDATE CASCADE ON DELETE CASCADE are introduced. I tried to run the statements with the keywords in MS Access 2013's SQL view. There is an error message saying
"Syntax error in CONSTRAINT clause."
The statements work perfectly without ON UPDATE CASCADE ON DELETE CASCADE.
The note in the book explain the keywords don't work on the version before SQL-92. I guess Access 2013 is way after SQL-92.
Can anyone explain to me why the keywords don't work?
below is the statements (ON UPDATE CASCADE ON DELETE CASCADE is at the end):
CREATE TABLE tblManufacturers
(
ManufacturerID INTEGER CONSTRAINT ManfID PRIMARY KEY,
ToyID INTEGER NOT NULL,
CompanyName CHAR (50) NOT NULL,
Address CHAR (50) NOT NULL,
City CHAR (20) NOT NULL,
State CHAR (2) NOT NULL,
PostalCode CHAR (5) NOT NULL,
AreaCode CHAR (3) NOT NULL,
PhoneNumber CHAR (8) NOT NULL UNIQUE,
CONSTRAINT ToyFk FOREIGN KEY (ToyID) REFERENCES tblToys (ToyID)
ON UPDATE CASCADE
ON DELETE CASCADE
);
Those keywords don't work because DAO doesn't support them. Built-in query builder also uses DAO. If you want to create table using CASCADE keywords, it can be done in VBA using ADO only:
CurrentProject.Connection.Execute strSQL
strSQL here contains CREATE TABLE statement
The ON UPDATE CASCADE and ON DELETE CASCADE statements are not supported by Access (see https://msdn.microsoft.com/en-us/library/office/ff836971.aspx).
Regarding the functionality, you should not have a need to use ON UPDATE CASCADE. This constraint means that if you do change a primary key in the master table, the changes propagate to every child table referencing the master table. Changing a primary key is considered a no-go in the SQL world. Is you really must change primary keys (because of some kind of disaster struck), this will be done with a script, lots of backup and extreme care. A primary key is this: a unique (ideally globally), immutable identifier of a row in a table.
The ON DELETE CASCADE means that if you remove a row in the master table, any rows referencing this key in child tables will also be deleted. While this sounds like a lazy shortcut, I would recommend against it and doing this within application logic (there might be a use case where you want to retain records or log them or do something with them instead of blindly erasing them from the database.
Related
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
I have two tables in SQL Server, one named Users and the other named Connections and connections is simply a connection between user and another user so my tables are like:
CREATE TABLE Users(
UserUID int IDENTITY NOT NULL,
UserUN NVARCHAR(100) NOT NULL,
UserPassword NVARCHAR(100) NOT NULL,
PRIMARY KEY(UserUID)
)
CREATE TABLE Connections(
_CID int IDENTITY NOT NULL,
_UID1 int not null,
_UID2 int not null,
_ConDate datetime null DEFAULT GETDATE(),
PRIMARY KEY(_CID),
FOREIGN KEY(_UID1) REFERENCES Users(UserUID) ON DELETE CASCADE,
FOREIGN KEY(_UID2) REFERENCES Users(UserUID) ON DELETE CASCADE
)
But every time I run the query it throws error:
Introducing FOREIGN KEY constraint 'FK_Connectio__UID2__69B1A35C' on table 'Connections' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
I tried searching in google and i found an answer that says I should do a trigger, but I don't know what is that. I hope I can find some answers and thanks a lot.
The problem with the table structure you're trying to define is:
Suppose you have a record in Users with ID 1, and a record in Connections with _UID1 = 1, and _UID2 = 1 too. Logically, in this case, that makes little sense, but the database does not know what Users means, nor what Connections means.
Now, you delete that user. Because of the ON DELETE CASCADE for _UID1, that Connections record should be deleted too. Because of the ON DELETE CASCADE for _UID2, that Connections record should be deleted again. This is a technical limitation in SQL Server, it just cannot handle multiple operations on the same row, and does not know how it should make sure the row is only deleted once in that case.
To prevent this problem, the ON DELETE CASCADE is simply not allowed in such a case where multiple updates of the same row could result.
I tried searching in google and i found an answer that says I should do a trigger, but I don't know what is that.
A trigger is a custom action, that can contain arbitrary SQL commands, that would automatically run after (or even "when") you make any modifications in a table. I could explain in more detail, but unlike what you found, I don't think you should do that.
Instead, if you want to delete user 1, I would recommend writing it as two separate DELETE statements:
DELETE Connections WHERE _UID1 = 1 OR _UID2 = 1;
DELETE Users WHERE UserUID = 1;
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.
The below statement is being used to create a table CAMPUS. I am getting the Error:
"Syntax error in CONSTRAINT clause"
"UPDATE" is highlighted signifying source of error.
By removing "ON UPDATE CASCADE ON DELETE NO ACTION" I am able to create the table with no issues.
What is the proper syntax or procedure? (the MS Access "Help" was of no help)
SQL Code:
CREATE TABLE CAMPUS(
CampusID Counter(1,5) NOT NULL,
UnivID Long NOT NULL,
CampusName Text(50) NOT NULL,
Address Text(50) NULL,
Zip Number NULL,
Phone Number NULL,
CONSTRAINT CampusPK PRIMARY KEY (CampusID,UnivID),
CONSTRAINT CampusFK FOREIGN KEY (UnivID)
REFERENCES UNIVERSITY(UnivID)
ON UPDATE CASCADE
ON DELETE NO ACTION
CONSTRAINT CampusAK1 UNIQUE (CampusName)
);
Access (ACE, Jet, whatever) has supported referential actions in its SQL DLL since Jet 4.0 (Access2000). However, they are only available in ANSI-92 Query Mode.
With effect from Access2003, the Access UI can be placed in ANSI-92 Query Mode, allowing the newer, richer SQL DDL to be executed from the SQL View of a Query. Note that ADO (OLE DB) always uses ANSI-92 Query Mode and DAO uses "traditional" ANSI-89 Query Mode (however IIRC DAO's object model has been enhanced to include all referential actions including the post-89 SET NULL action).
Therefore, I speculate that you are getting a syntax error because your are trying to execute ANSI-92 Query Mode SQL DDL while in ANSI-89 Query Mode.
It's been more then 10 years since I last used MS Access, but it seems you can only write either CASCADE or SET NULL after ON UPDATE and ON DELETE in a referential constraint.
So basically you have to omit this part
ON DELETE NO ACTION
Link http://www.sqlexamples.info/SQL/bsc_sqlddl1.htm
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?