I have two primary (composite) keys that refer to a shop and a branch.
I thought I should have used a corresponding ID for each row, so I added a UNIQUE + AUTO_INCREMENT named ID.
So I had on the table a column named ID (AUTO INCREMENT), but it was declared PRIMARY - which was done automatically, and I don't want the ID to be PRIMARY. Just the shop and branch.
I have learnt how to trick MYSQL to accept the ID field as UNIQUE and AUTO INCREMENT, as it was not extremely trivial to make the AUTO_INCREMENT (it wanted to make it PRIMARY).
I had to ERASE the ID Field (for some reason it didn't let me erase its PRIMARY index), then declare it INDEX, and only then AUTO INCREMENT.
Is that a good approach ?
Could there be something I am doing wrong going with this design ?
Thanks !!!
The prevailing wisdom is that every table should have a unique autonumbered column named Id.
In classical data modeling, as developed by Codd and Date, the ID field is not necessary for a complete logical model of the data.
What good does the ID field do you? Do you ever reference a row in this table by its ID? If never, then just leave the field out. (shop, branch) provided a perfectly good candidate to be the PK.
What did your create table statement look like? Because I imagine this:
CREATE TABLE foo (
IDCol int not null auto_increment,
shop int not null,
branch int not null,
/* ... */
UNIQUE KEY IDCol (IDCol),
PRIMARY KEY (shop, branch)
);
Related
I have a table with the following structure
CREATE TABLE Products (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(30) NOT NULL,
code VARCHAR(30) NOT NULL UNIQUE,
warranty TINYINT(1) NOT NULL,
producing_country VARCHAR(50),
)
Each product in my table has a unique code and This products is also known in stock as this codes
Codes are something like this: (AR-X22 , RF-3654, ...)
My question is can i remove the ID cloumn in this table? Because it has no special application
And does it hurt if I want to use the code column instead of id in join ?
Its good practice to have a table with an id INT AUTO_INCREMENT and PRIMARY KEY.
It makes sure each row is unique. If other programmers come and look at your table they will expect to see an id column.
Having a VARCHAR as a unique row key is is asking for trouble. There are all sorts of encoding troubles and things that can make strings as identifiers unreliable.
For example: "ABX-112" and "ABX -112" (space hidden in there)
If you just don't want to see ID column do like ravioli states below and just make a new view and not show it.
Good luck.
Your id column is specified as your PK, which means it's used to uniquely identify that row in your table. It looks like it's an identity-type field, which should take care of the uniqueness requirement.
If you want to use code as your new "id" field, that should be fine as long as you make sure it's a unique value when you add rows. It shouldn't have any effect on joins as long as you update your other tables to use the new code field.
I don't know how easy it is to fiddle with PK's on a table that already has data. Your best bet is to create a new table without the id field and populate it using the data in your current table.
If it's just a matter of not wanting to see / deal with an id field you never use, you can always create a view and exclude that field from being returned.
As per my understanding, You want to remove Id from the table and want to use Product code at that place.
A table relationship is based on the primary and foreign key constraints and it is not necessary that every time you have to Id column as primary key.
If you have product code and which will always be unique and not null
then you can use Code as the primary key for the table rather then
unnecessary Id column.
It will also work if you do not create a column wither primary.
Thanks.
I've heard Primary Key means to be unique. Correct me please if I'm wrong.
Assume we have a table of users. It has 3 columns of id, username and password. We usually set the id to be AUTO_INCREMENT. So it would technically make a new unique id each time we add a row to the table. Then, why we also set the id column to be Primary Key or Unique?
Having a column as a key offers other aspects. First, if it is primary or unique, this would enforce that no query could enter a duplicate value for that key. Also keys can allow you do things like
INSERT ... ON DUPLICATE KEY UPDATE...
Of course you also want an index on the column for quick lookups.
AUTO_INCREMENT behavior only manifests when the column is not specified during an insert. Consider:
CREATE TABLE ai (
ai int unsigned not null auto_increment,
oi int unsigned,
key (ai),
primary key (oi)
);
INSERT INTO ai VALUES (1,2);
INSERT INTO ai VALUES (1,3);
INSERT INTO ai VALUES (null,5);
This will yield (1,2), (1,3), (2,5). Note how the AUTO_INCREMENT column has a duplicate.
A primary key does two things:
enforce database integrity (uniqueness and not-null of the column)
create an index to implement that, which also makes for fast look-up by the primary key column as a "side-effect".
You may not strictly need (1) if you can ensure that in your application code (for example by only using the auto-increment value), but it does not hurt.
You almost certainly want (2), though.
So it would technically make a new unique id each time we add a row to the table
Well, that is up to you. The unique id only gets inserted if you don't specify an explicit value. And technically, it is not guaranteed to be unique, it is just an auto-increment that does not take into consideration any existing values in the table (that may have somehow ended up in there).
Let's say I have a table with the following fields:
primaryEmail | secondaryEmail
I know how to create a UNIQUE constraint on one of the fields, and I know how to create a UNIQUE constraint that combines both fields, but is there a way to ensure that no value exists twice, ACROSS both columns? For example, if there's a value of joe#example.com in the primaryEmail field, I don't want it to be able to appear again in either the primaryEmail field OR the secondaryEmail field.
You might consider revising your data model and pulling the email address to another table and then relating the new and old tables together. Off the top of my head, something like this should work
create table master (
id int not null primary key,
name varchar(64)
);
create table email (
id int not null primary key,
address varchar(128) not null unique,
parent_id int not null,
type enum('prim', 'secd'),
foreign key (parent_id) references master(id)
on delete cascade,
unique (parent_id, type)
);
I don't love this design - I'm not a fan of the enum, for example - but it would solve your uniqueness constraint.
In my opinion, you would want to put two separate constraints on that field if that is really what you are trying to accomplish. What you are actually trying to do are two different things (make sure that column is unique within the record, and make sure that column within that row is also unique for the whole table).
I have a Questions table which looks like that
as you see, there are 2 id rows that are nearly same: id, question_id. id - is autoincremented, unique id of each question, and question_id - is, for example, course 1 lesson 1 has 5 questions like: question 1, 2, 3, 4, 5. And course 1 lesson 2 has 3 questions: 1, 2, 3 etc.. In other words it's like autoincrement field for each unique course_id, lesson_id combination. I decided to add manually question_id based on course_id, lesson_id for keeping database structure readability and not messing up database, with bunch of association tables between course-lesson-question unique id values.
First question is
How do you think, is it good solution or not? How you'd design this database?
The problem is, when I want to insert new question with given course_id, lesson_id the id field will auto-increment, but I got
Second question
How can I get, last question_id column value based on unique course_id, lesson_id combination. For example, if course 1 lesson 2 has 3 questions: 1, 2, 3 and I want to add 4th question (as I said, in current db design I'm inserting question_id value manually), how do I know that, the last question of course 1 lesson 2 is 3th, and insert new question with (last_number=3)++=4?
Update
Situation is a bit complicated but I will try to explain:
It's online tutorials website. There are different courses, and each course has bunch of lessons. Now I'm designing question-answer part, in which teacher posts questions, and users getting dedicated questions.
Full size image here
Now, the table questions is dedicated for course>lesson based questions.
question_from_to_assoc - It's for, creating assoications between question author and receiver user. For example admin (id=.) sends question to some user with id=5.
qa_assoc - question-answer associations table.
First of all, this is not an optimal database design. Your schema is denormalized, which is not really good.
To answer your first question. I would split Lesson, Course, Question and Author into separate tables. Then I would add a number field beside the Primary Key for Course, Lesson and Question. The PK will only ensure uniqueness of a row, but the number field will be your course number, question number, etc.
Using the PK to represent a question number for instance is not a good idea in my opinion, because it should be kept unchanged. For instance, if your questions are changed to letters instead of numbers, your PK would have to be changed and this might break referential integrity.
After that, I would add a unique constraint on question numbers and FK like [question_no, lesson_id] to ensure that you cannot have two question 1 for the same lesson. Same thing for Lesson. Course would have a unique constraint on course_no.
Finally, to automatically increment question numbers depending on lesson, I would use a trigger which would do something like :
CREATE TRIGGER tr_question_number BEFORE INSERT ON questions
FOR EACH ROW BEGIN
SET NEW.question_no = (SELECT MAX(question_no)+1 FROM questions WHERE lesson_id = NEW.lesson_id FOR UPDATE)
END;
This trigger will set the question number field with the latest value + 1. The FOR UPDATE clause is very important, because it will lock the row to avoid concurrent insertion to get the same number.
The trigger is just a draft, but that's just a general idea of what I would have done.
I hope this will help you.
Question 1: No. I would just use that ID column in that questions table as your unique identifier and drop that question_id field. My design:
create table author (
id int(11) NOT NULL auto_increment,
name varchar(256)
) engine=innodb;
create table course (
id int(11) not null auto_increment,
primary key(id),
name varchar(256)
) engine=innodb;
create table lesson (
id int(11) not null auto_increment,
primary key(id),
name varchar(256),
course_id int(11) NOT NULL,
FOREIGN KEY(course_id) references course(id)
) engine=innodb;
create table question(
id int(11) not null auto_increment,
primary key(id),
question_text text,
correct_answer text,
lesson_id int(11) NOT NULL,
foreign key(lesson_id) references lesson(id),
author_id int(11) not null,
FOREIGN KEY(author_id) REFERENCES author(id)
) engine=innodb;
Question 2: Don't do that. What if I have course_id 1, lesson 2, and question 11? That ID column would be identical to course_id 1, lesson 21, question 1.
And as an aside, I really hope you're using foreign keys. Since it says you're using mysql, be sure to use the Innodb storage engine with these tables so you can use foreign keys to enforce referential integrity.
The key to querying this database efficiently, avoiding collisions in supposedly unique values, avoiding serious performance issues in the future, and data duplication is to design your database in a normalized manner. My example above is normalized and avoids data duplication, as well as the composite key scheme that would not result in unique keys that you defined above. It's best to work with the features built into MySQL rather than try to reinvent the wheel.
I personally would set this up different:
Question table:
id int, -- PK auto-increment
content varchar(50),
answer varchar(50),
authorid int
Course table:
id int, -- PK auto-increment
name varchar(50)
Lesson Table:
id int, -- PK auto-increment
name varchar(50)
Question_Course_Lesson join table:
questionid int, -- PK
courseid int, -- PK
lessonid int -- PK
1.
You should try to get rid of question_id and only leave the autoincrement id as a primary key. Otherwise inserting will get messy.
The problem is, now when I want to insert new question with given course_id, lesson_id the id field wil auto-increment.
I don't understand the problem - auto_increment fields usually do that :).
2.
You can use
SELECT MAX(question_id) WHERE course_id = <something> AND lesson_id = <some_other_thing>
To get the current max id for a given course_id and lesson_id. But you will have to lock the table (or use FOR UPDATE and a transaction if the table is InnoDB) and unlock it after you insert the new record to make sure it remains consistent.
First question.
Actually, I can see why you might need the "redundant" id.
For example, it may play a role in the process of presenting your questions to test takers.
But, it surely does not need to be tied to the values of other columns in the row, the autogenerated id guarantees uniqness anyway.
Second question.
Use the onInsert trigger. It the best way to prevent collisions.
I am using MySQL for my database. I have a requirement to store a list of users in the system. The user will have both first name and last name.
I cannot have the first name and second name as the primary key. So I need a indexing key. But I do not want to enter the index value every time to add a new row.
I want the system to handle this with auto increment of previous value every time I try to add a new user. Please let me know how to do this.
Also I am supposed to do a search operation on the list of user with the first name. Please let me know the efficient way to do the search as the number of records could be more than a million.
create table users (
id int primary key auto_increment,
name varchar(64),
...
)
See here for more info
Add an INT() id column with auto_increment set. This way, the id column value will be incremented automatically on each INSERT.
To get a unique key without having to specify it, you need an auto_increment field:
create table people (
person_id int primary key auto_increment,
first_name varchar(50),
: : :
);
For efficiently searching first names, you just need an index on the first-name column. A couple of million rows is not a big table, so this should be reasonably efficient.
create index person_index using btree on people (first_name);