how database foreign keys cascade mysql - database

I created a set of tables in a database.A assigned relations with foreign key.
i am not getting cascading effect of data in mysql.
i created a table named ME and with MY_ID column name
I also created table named MY_Friends with MY_ID column name and foreing key with references to ME(MY_ID).
I am able to notice cascading effect in mysql
Me
My_ID | int(11) | NO | PRI | 0
My_Friends
My_ID | int(11) | YES | MUL | NULL | |
there are two columns description in two tables

FOREIGN KEY and CASCADE will have no effect if the tables are MyISAM. Check if the tables are defined using the InnoDB engine. Give us the output from SHOW CREATE TABLE Me and SHOW CREATE TABLE My_Friends so we can verify if that's the problem.

Related

Is there an easy way to reference multiple primary keys in one column of destination table?

I apologize for my lack of knowledge or incorrect usage of terms; I am taking an online DBMS course and it is mostly self-taught with Microsoft SQL Server.
We are tasked with creating a database design and inserting data into it for something that interests us. I chose to create a database based on Dungeons and Dragons, and had a question on if I was doing something correctly.
I intend to create a Spell_Source table that will hold the primary key of multiple different tables (Class and Subclass) as one column, and the name of the spell (a primary key in a different table) as the other. When I go to input the data however, the foreign key constraints are stopping the insertion.
I am fully prepared to redesign the database itself if it's a problem in normalization, or if there's a simple fix that I'm missing due the self-taught nature of the class.
Thanks for your help!
CREATE TABLE SPELL_SOURCE (
SpellName VarChar(50) NOT NULL,
SpellSource Char(25) NOT NULL,
CONSTRAINT SpellSourcePK1 PRIMARY KEY (SpellName, SpellSource),
CONSTRAINT SpellSourceFK FOREIGN KEY (SpellName)
REFERENCES SPELLS(SpellName)
ON UPDATE NO ACTION
ON DELETE NO ACTION,
CONSTRAINT SpellSourceFK1 FOREIGN KEY (SpellSource)
REFERENCES CLASS(ClassName)
ON UPDATE NO ACTION
ON DELETE NO ACTION,
CONSTRAINT SpellSourceFK2 FOREIGN KEY (SpellSource)
REFERENCES SUBCLASS(SubclassName)
ON UPDATE NO ACTION
ON DELETE NO ACTION
);
The exact error I'm getting from the Import Data tool is "The INSERT statement conflicted with the FOREIGN KEY constraint "SpellSourceFK1". The conflict occured in database table "dbo.CLASS", "ClassName""
The problem is that you entered a value for SpellSource that has no corresponding ClassName in table CLASS. A column can be part of different Foreign Keys if those are different compound keys. E.g. FK (a, b), FK (b, c) where b belongs to 2 FKs. But otherwise a single column (as a rule of thumb) should have only one FK.
Also, if you have classes and subclasses, you would only reference the subclass here and create a 1 to n relationship between class and subclass. I.e., subclass would have a foreign key for ClassID
SPELL_SOURCE SPELLS
+------------- ---+ +---------------+
| PK FK SpellID | o-----> | PK SpellID |
| PK FK SubclassID | o--+ | SpellName |
+------------------+ | +---------------+
|
| SUBCLASS CLASS
| +-----------------+ +---------------+
+--> | PK SubclassID | +--> | PK ClassID |
| SubclassName | | | ClassName |
| FK ClassID | O--+ +---------------+
+-----------------+
Don't use the names as PK. It will make it very difficult to change names later. Instead only reference an int IDENTITY(1,1) (auto incrementing) primary key that never changes and store the name in a separate column that you can edit at any time. See: CREATE TABLE (Transact-SQL) IDENTITY (Property).
You can query the combined information with
SELECT
SS.SpellID, SS.SubclassID,
S.SpellName,
C.ClassName,
SC.SubclassName, SC.ClassID
FROM
SPELL_SOURCE SS
INNER JOIN SPELLS S
ON SS.SpellID = S.SpellID
INNER JOIN SUBCLASS SC
ON SS.SubclassID = SC.SubclassID
INNER JOIN CLASS C
ON SC.ClassID = C.ClassID
ORDER BY
C.ClassName, SC.SubclassName, S.SpellName
But note that with this design, the same spell could belong to different classes and subclasses. If a spell can belong to only one subclass, then the structure should look like.
Class 1 --> n Subclass 1 --> n Spell
According to your comments a spell could belong to a class instead of a subclass (and indirectly to a class also). Then I would suggest the following structure
SPELL_SOURCE (separate PK because of nullables, Unique Constraint UC instead)
+------------------+ SPELLS
| PK SpellSourceID | +---------------+
| FK UC SpellID | o---------> | PK SpellID |
| FK UC SubclassID | o------+ | SpellName |
| FK UC ClassID | o--+ | +---------------+
+------------------+ | |
| | SUBCLASS CLASS
| | +-----------------+ +-----> +---------------+
| +--> | PK SubclassID | | +--> | PK ClassID |
| | SubclassName | | | | ClassName |
| | FK ClassID | o--+ | +---------------+
| +-----------------+ |
| |
+----------------------------------+
Where in SPELL_SOURCE both ClassID and SubclassID are NULLABLE. Always only one of the two would be not null. You could add a CHECK constraint (ClassID IS NULL AND SubclassID IS NOT NULL) OR (ClassID IS NOT NULL AND SubclassID IS NULL). And use LEFT JOINS in the query.
See: http://www.sqlfiddle.com/#!18/107dd/3/0
Yet another approach would be to keep the first structure but to have a main or default subclass entry in each class. E.g., a subclass having a SubclassName = NULL. This entry would be representative of the class.
For drop-down-lists you could select the entries like this
SELECT
S.SubclassID,
CASE WHEN S.SubclassName IS NULL THEN
'CLASS: ' + C.ClassName
ELSE
S.SubclassName + ' (' + C.ClassName + ')'
END AS Name
FROM
CLASS C
INNER JOIN SUBCLASS S
ON C.ClassID = S.ClassID
ORDER BY
C.ClassName,
CASE WHEN S.SubclassName IS NULL THEN 0 ELSE 1 END,
S.SubclassName
See: http://www.sqlfiddle.com/#!18/d8777/1/0
Just wanted to throw my support behind the answer from #Olivier's response. You're going to cause yourself a lot of grief attempting to move forward with your current design.
However by creating a 1 -> N relationship between your SubClass and your Class you will always maintain referential integrity, and your Class will easily be queried through the sub-class

TSQL, delete row and all foreign key related rows

I am wondering if there is a query for deleting a row which also deletes all related foreign key related data.
I have a database with a table which refers through a foreign key to other rows in the same table
ID | ParentID | Data fields
1 | NULL | text and more data
2 | 1 | Text and more data
3 | 2 | ""
As you see item 2 refers to 1 using a foreign key. Currently I am unable to delete object 1 because object 2 and 3 still exist in the database. I want to know if there is a way/query (without changing the table settings) to delete object 1 and therefore also deleting 2 and 3.
DELETE FROM Table WHERE ID = 1 -- And this must then also delete row 2.
DELETE FROM Table WHERE ID = 1 OR ParentID = 1 -- Obviously doesn't work either.
I am aware that it is possible to turn of foreign key constrainst for a table, but I want to know if it can be done with a query without changing these settings.
Best way would be enabling CASCADE DELETE.
Read more here: How do I use cascade delete with SQL Server?

postgresql: change primary key

Until now I had a column account_name as the primary key for my database. I'd now like to use a hash of account_name as the primary key instead.
So as an interim measure, I added an account_hash column and gave it the UNIQUE constraint, so that both account_name and account_hash exist together.
I populated account_hash for all database entries, and am now actually using account_hash as the key for the database, and am no longer actively using account_name for anything.
But of course because account_name is the "official" primary key, and must be NOT NULL, for any new entries I have been populating both account_name and account_hash with the same hash.
It's all working fine like this, but now I'd like to clean up the database, to get rid of account_name entirely, and to make account_hash the primary key instead.
What is the best way of doing this? It is a working database that is in use constantly, so any change needs to be at minimum disruption to the users.
Here is the \d+ information relating to the relevant columns:
Column | Type | Modifiers | Storage | Stats target | Description
-------------------------------+------------------------+-----------------------------+----------+--------------+-------------
account_name | character varying(255) | not null | extended | |
account_hash | character varying(256) | | extended | |
Indexes:
"users_pkey" PRIMARY KEY, btree (account_name)
"users_account_hash_256_key" UNIQUE CONSTRAINT, btree (account_hash)
Has OIDs: no
Thanks for any help!
You can drop the current primary key with
ALTER TABLE tablename DROP CONSTRAINT users_pkey;
Make the account_hash required with
ALTER TABLE tablename ALTER account_hash SET NOT NULL;
After that you can add a new primary key with
ALTER TABLE tablename ADD PRIMARY KEY USING INDEX indexname;
You may have to drop the users_account_hash_256_key constraint first to not have a duplicate and depending on how the unique index was created, you may have to create the index again for this.
If the account_name column is not used anywhere, it can then be dropped with
ALTER TABLE tablename DROP COLUMN account_name;
Note I would advise against this action. Hashes have collisions, so if you use them as primary keys, there may be a time when you cannot insert a value into the database because of that. Also performance is worse with varchar indexes than with integers (or a UUID, if a very large keyspace is needed), so if there is no specific reason for using hashes, I wouldn't do this.

Is it possible to have a foreign key which isn't covering the whole primary key of the referenced table?

I have two tables:
Table A: with a composite primary key.
CommonID (PK) | Month (PK) | some data...
-----------------------------------------
1 | May 2011 | ...
1 | June 2011 | ...
2 | May 2011 | ...
2 | June 2011 | ...
Table B: referencing to table A
ID (PK) | A_CommonID (FK)| some data...
-----------------------------------------
... | 1 | ...
... | 2 | ...
As you can see table B isn't referencing the whole primary key but it will definitely always reference a unique entry in table A because there is a global value for the specified used month which will be used for A.Month in SQL-queries.
Now my question is, is that allowed or am I violating several rules of Database design?
I would really appreciate a nice answer because I will use it in the final document which I have to write for my bachelor's degree.
Thanks a lot in advance!
No, this is not allowed.
If you have a composite primary key consisting of more than one column, your foreign keys must also be composite and reference all the columns involved in your primary key.
A foreign key must reference the primary key, the whole key and nothing but the key (so help you Codd) :-)
What you might be able to do is to have a separate unique index on that A_CommonID column in Table A so that your Table B can reference that unique index (instead of the PK).

(PostgreSQL) "Advanced" Check Constraint Question

I use PostgreSQL but am looking for SQL answer as standard as possible.
I have the following table "docs" --
Column | Type | Modifiers
------------+------------------------+--------------------
id | character varying(32) | not null
version | integer | not null default 1
link_id | character varying(32) |
content | character varying(128) |
Indexes:
"docs_pkey" PRIMARY KEY, btree (id, version)
id and link_id are for documents that have linkage relationship between each other, so link_id self references id.
The problem comes with version. Now id is no longer the primary key (won't be unique either) and can't be referenced by by link_id as foreign key --
my_db=# ALTER TABLE docs ADD FOREIGN KEY(link_id) REFERENCES docs (id) ;
ERROR: there is no unique constraint matching given keys for referenced table "docs"
I tried to search for check constraint on something like "if exists" but didn't find anything.
Any tip will be much appreciated.
I usually do like this:
table document (id, common, columns, current_revision)
table revision (id, doc_id, content, version)
which means that document has a one-to-many relation with it's revisions, AND a one-to-one to the current revision.
That way, you can always select a complete document for the current revision with a simple join, and you will only have one unique row in your documents table which you can link parent/child relations in, but still have versioning.
Sticking as close to your model as possible, you can split your table into two, one which has 1 row per 'doc' and one with 1 row per 'version':
You have the following table "versions" --
Column | Type | Modifiers
------------+------------------------+--------------------
id | character varying(32) | not null
version | integer | not null default 1
content | character varying(128) |
Indexes:
"versions_pkey" PRIMARY KEY, btree (id, version)
And the following table "docs" --
Column | Type | Modifiers
------------+------------------------+--------------------
id | character varying(32) | not null
link_id | character varying(32) |
Indexes:
"docs_pkey" PRIMARY KEY, btree (id)
now
my_db=# ALTER TABLE docs ADD FOREIGN KEY(link_id) REFERENCES docs (id) ;
is allowed, and you also want:
my_db=# ALTER TABLE versions ADD FOREIGN KEY(id) REFERENCES docs;
of course there is nothing stoping you getting a 'combined' view similar to your original table:
CREATE VIEW v_docs AS
SELECT id, version, link_id, content from docs join versions using(id);
Depending on if it's what you want, you can simply create a FOREIGN KEY that includes the version field. That's the only way to point to a unique row...
If that doesn't work, you can write a TRIGGER (for all UPDATEs and INSERTs on the table) that makes the check. Note that you will also need a trigger on the docs table, that restricts modifications on that table that would break the key (such as a DELETE or UPDATE on the key value itself).
You cannot do this with a CHECK constraint, because a CHECK constraint cannot access data in another table.

Resources