Multiple foreign key for 'extra data' table - mysql

i have a logical question for optimization tables relation in MySQL (and even other DBMS).
there are many table with different columns and structures in my database. for a specific reason, i need to create a new table, names "extra_data" with there columns (id, table, content). each table (even "extra_data" itself) MAY needs to store extra data for undefined columns. so this extra data that is a PHP array or object, first serialized and then transform to Base64 code and inserted to "eaxtra_data" table content column. id and table name of target table row, stored in id and table columns in "extra_data" too.
for example if there is two tables names "users" and "posts" and each of them need to store extra data in "extra_data" table:
"users" table:
id name gender ...
1 Tom Male ...
2 Mary Female ...
3 Jack Male ...
...
 
"posts" table:
id title date ...
1 news 4/11/2014 ...
2 article 4/51/2014 ...
...
 
"extra_data" table:
id table content
1 users #$!^...
2 users #$!^...
2 posts #$!^...
...
id and table is primary key in "extra_data" table. so problem is when target row (form example row 2 in users) has been changed or removed, related row in "extra_data" must updated automatically if it's necessary. but the way to set foreign key in many table and in two columns (id, table) together, is imprecise to me! thanx for any help

DarkMaze,
I see where you come from with this "extra_data" table. I don't agree, though. Once it goes against the principles of database normalization and this logic is not clear on a design perspective. I'd rather serialize whatever data you want to add to extra_data content column and save it into its respective table.
Back on the question, the only solution I see so far is to add triggers on every table related to "extra_data" in order to add/remove/update records. Which is not very productive.
Cheers,
http://en.wikipedia.org/wiki/Database_normalization

Related

Insert an entire column content into another table plus a value

Ok, I am new to SQL, so this must sound stupid. Sorry for that.
I have two tables + one junction table (many to many schema) = total of three tables.
First table
students: student_id (PRIMARY) | name | email | password |...
Second table
topics: topic_id (PRIMARY) | topic_name | subject |...
Third table (junction)
jnct_students_topics: id (PRIMARY) | student_id_FK | topic_id_FK | done (boolean) | notes
So how the web app would work?
Second table (topics) is pre-filled with all the topics students need to study.
First table (students) will be filled whenever a new student register for the service.
Junction table (jnct_students_topics) will also be filled when student registers, but (HERE COMES THE QUESTION) I need to know how to insert all topics ids + this student id in topic_id_FK and student_id_FK columns.
Because when a student registers, system will create a list for him/her with all topics to study and a checkbox for each one. After student finishs with topic studying, he/she will check the box and the boolean done column will become true for this topic.
I learned from [this question] (Copy from one column to another (different tables same database) mysql) that, to populate a table column with values from another table column, I could go:
INSERT INTO jnct_students_topics (topic_id_FK)
SELECT topic_id
FROM topics
but I need to build the statement so at the same time the student_id (related to the student that is registering) is inserted (column student_id_FK) in all rows that are being created.
Tired of reading? Well, I don't blame you. Nor english or SQL are native languages of mine... :)
By the way, If you think that this schema is not the best, please, I would appreciate some advice.
Thanks!

Prevent duplicate entries in a database table based on 2 columns

I record the datas of a competition in an MySQL database.
I need to have unique entry for each player so i’ve done this :
alter table xtu_datas_competition add unique index(email);
It works perfectly.
But there are several competitions, so i have also a colum id_ competition and i want to have unique entry for email and for specific colum id_ competition
For example :
2 identical email for 2 identical colum id_ competition : duplicate
2 identical email for 2 different colum id_ competition : not duplicate
How can i adapt my previous code ?
You simply have to define a unique constraint containing both columns:
alter table xtu_datas_competition add unique index(id_competition,email);
Hope this will help you.

mysql - It is ok to have n amount of columns?

I know it's possible to have n amount of columns, but is it proper mysql "coding standard"?
Here is what I'm doing:
I am a table student which includes all the students info including testScores:
student
-------
studId
name
age
gender
testId
Instead of putting each individual test answer within the student table, I made a separate table called testAnswers that will hold each students test results:
testAnswers
-----------
testId
ques1
ques2
.
.
.
quesN
Each entry in the testAnswers table corresponds to a specific student in the table student.
Of course, there will be an admin that will be able to add questions and remove questions as each year the test questions may change. So, if the admin were to remove an answer, than that means one of the columns would be removed.
Just to reiterate myself, I know this is possible to edit and remove columns in a table in mysql, but is good "coding standard"?
The answer is a simple and clear: No. That's just not how you should do it except for very few corner cases.
The usual way to approach this is to normalize your database. Normalization follows a standard procedure that (among other things) avoids having a table with columns names ques1, ques2, ques3 ....
This process will lead you to a database with three tables:
students - id, name, and other stuff that applies to one student each
questions - id and question text for each question
answers - this is a N:M relation between students: student_id, question_id, answer_value
Use two tables!
What you are describing is a one to many relationship as there can be one student to many test scores. You would need to have some id as a foreign key to the student_id and put this id in the testAnswers table. You can then set constraints, which tell the database how to handle removal of data.
As one commenter has mentioned, using one table would result in breaking 1nf or first normal form which basically says that you cannot have multiple values for a single column given a particular record - You can't have multiple test scores for the same user in a given table, instead break the data up into two tables.
...of course 2 tables, also could use 3, just remember to insert a studId column also in the testAnswers table (with REFERENCE to the student table) and an INNER JOIN testAnswers ON student.studId=testAnswers.studId at the SELECT query (to read the data).

Comments on many tables database design issue

I have tables:
Articles{...}
Recipes{...}
Notifications{...}
Photos{...}
And I need to implement 'user comments' feature (like facebook).
Should I make tables: ArticleComments, RecipesComments etc. with 1:n relationship?
Or create one Comments table for all (but I have no idea how to design this)?
You could create another table CommentableEntity (although call it something better). Each of the rows in your tables (Articles, Recipes etc.) would have a reference to a unique row in this table. The entity table might have a type field to indicate the type of entity (to aid reverse joining).
You can then have a Comment table that references CommentableEntity, in a generic fashion.
So for example you'll end up with the following tables:
Articles
-----------------
Article_id
CommentableEntity_id (fk, unique)
Content
....
Recipes
-----------------
Recipe_id
CommentableEntity_id (fk, unique)
Content
....
CommentableEntity
-----------------
CommentableEntity_id (pk)
EntityType (e.g. 'Recipe', 'Article')
Comment
-------
Comment_id (pk)
CommentableEntity_id (fk)
User_id (fk)
DateAdded
Comment
...etc...
You can add the CommentableEntity record every time you add an Article/Recipe etc. All your comment-handling code has to know is the CommentableEntity_id - it doesn't care what type of thing it is.
That depends on how your application will be using comments.
My guess is that you'll frequently want to pull up all the comments a user has created regardless of the entity that they are commenting on. That is, I assume you'll frequently want a query that returns rows indicating that user JohnDoe commented on Article 1, then Photo 12, then Recipe 171. If that's the case, then it would make far more sense to have a single Comments table with a structure similar to what Steve Mayne has suggested with the CommentableEntity table.
On the other hand, if you would only be accessing the comments for a particular item (i.e. all comments for Article 1), separate ArticleComments and PhotoComments tables may be more appropriate. That makes it easier to have foreign keys between the entity table and the comment table and is potentially a bit more efficient since it's a poor man's partitioning. Of course, as soon as you start having to combine data from multiple comment tables, this efficiency goes away so you'd need to be reasonably confident about the use cases.
The easiest way would to have a 'polymorphic' comments table that would have columns for both the id and the type of the object that it refers to.
The you could do the following:
SELECT * FROM Comments where type = "Articles" and type_id = 1;
SELECT * FROM Comments where type IN ("Recipes", "Photos")
Putting a unique compound index on (type, id) would also improve the performance of the look ups.
SELECT TOP 1000 [Comments_Id]
,[Comments_Text]
,[Comments_IsApproved]
,[Comments_IsVisible]
,[Comments_DateStamp]
,[Type_Id]
,[Entity_Id] -- From Entity Table, listing Articles, Recipes etc.
,[EntityItem_Id] -- One of the PK from table of Articles, Recipes etc.
,[User_Id]
FROM [tbl_Comments]
To have an idea on how to create a single Comments table for all objects, you can take a look at django comment model ( http://docs.djangoproject.com/en/dev/ref/contrib/comments/models/ )

How to handle fragmentation of auto_increment ID column in MySQL

I have a table with an auto_increment field and sometimes rows get deleted so auto_increment leaves gaps. Is there any way to avoid this or if not, at the very least, how to write an SQL query that:
Alters the auto_increment value to be the max(current value) + 1
Return the new auto_increment value?
I know how to write part 1 and 2 but can I put them in the same query?
If that is not possible:
How do I "select" (return) the auto_increment value or auto_increment value + 1?
Renumbering will cause confusion. Existing reports will refer to record 99, and yet if the system renumbers it may renumber that record to 98, now all reports (and populated UIs) are wrong. Once you allocate a unique ID it's got to stay fixed.
Using ID fields for anything other than simple unique numbering is going to be problematic. Having a requirement for "no gaps" is simply inconsistent with the requirement to be able to delete. Perhaps you could mark records as deleted rather than delete them. Then there are truly no gaps. Say you are producing numbered invoices: you would have a zero value cancelled invoice with that number rather than delete it.
There is a way to manually insert the id even in an autoinc table. All you would have to do is identify the missing id.
However, don't do this. It can be very dangerous if your database is relational. It is possible that the deleted id was used elsewhere. When removed, it would not present much of an issue, perhaps it would orphan a record. If replaced, it would present a huge issue because the wrong relation would be present.
Consider that I have a table of cars and a table of people
car
carid
ownerid
name
person
personid
name
And that there is some simple data
car
1 1 Van
2 1 Truck
3 2 Car
4 3 Ferrari
5 4 Pinto
person
1 Mike
2 Joe
3 John
4 Steve
and now I delete person John.
person
1 Mike
2 Joe
4 Steve
If I added a new person, Jim, into the table, and he got an id which filled the gap, then he would end up getting id 3
1 Mike
2 Joe
3 Jim
4 Steve
and by relation, would be the owner of the Ferrari.
I generally agree with the wise people on this page (and duplicate questions) advising against reusing auto-incremented id's. It is good advice, but I don't think it's up to us to decide the rights or wrongs of asking the question, let's assume the developer knows what they want to do and why.
The answer is, as mentioned by Travis J, you can reuse an auto-increment id by including the id column in an insert statement and assigning the specific value you want.
Here is a point to put a spanner in the works: MySQL itself (at least 5.6 InnoDB) will reuse an auto-increment ID in the following circumstance:
delete any number rows with the highest auto-increment id
Stop and start MySQL
insert a new row
The inserted row will have an id calculated as max(id)+1, it does not continue from the id that was deleted.
As djna said in her/his answer, it's not a good practice to alter database tables in such a way, also there is no need to that if you have been choosing the right scheme and data types. By the way according to part od your question:
I have a table with an auto_increment field and sometimes rows get deleted so auto_increment leaves gaps. Is there any way to avoid this?
If your table has too many gaps in its auto-increment column, probably as a result of so many test INSERT queries
And if you want to prevent overwhelming id values by removing the gaps
And also if the id column is just a counter and has no relation to any other column in your database
, this may be the thing you ( or any other person looking for such a thing ) are looking for:
SOLUTION
remove the original id column
add it again using auto_increment on
But if you just want to reset the auto_increment to the first available value:
ALTER TABLE `table_name` AUTO_INCREMENT=1
not sure if this will help, but in sql server you can reseed the identity fields. It seems there's an ALTER TABLE statement in mySql to acheive this. Eg to set the id to continue at 59446.
ALTER TABLE table_name AUTO_INCREMENT = 59446;
I'm thinking you should be able to combine a query to get the largest value of auto_increment field, and then use the alter table to update as needed.