Which column should I make the primary key? - mysql

I'm making a table
Mobile Models Information
+-------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-----------------+------+-----+---------+----------------+
| ID | int(5) unsigned | NO | PRI | NULL | auto_increment |
| linktospecs | varchar(255) | YES | | NULL | |
| name | varchar(30) | NO | UNI | NULL | |
| company | varchar(20) | NO | | NULL | |
+-------------+-----------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)
In this table, each mobile from any handset maker will appear only once, and with it, other information like its manufacturer's name and an official link to its specifications. That's all I can think of now.
What I want is, that since the name column would be inherently unique (two rows of same mobile models would be stupid), I want to be able to index using it, simply, because in my application, when a user searches for a mobile name, I would use the name column to retrieve all other columns from this table.
But in many examples I have seen people use an extra simple ID column that auto increments to keep it as a simple primary key.
So, my question is, do I need to keep the ID column or should the unique name column be sufficient to use this table?
I'm new to databases and SQL.

Having an ID column as the primary key is always a good idea because it will never change. If you need to change the name of a phone, and name is the primary key, then any previous references to that phone will immediately stop working because the primary key value is no longer there. On the other hand, if you have a unique ID for each one, you can change the name without affecting the ID, and all previous references will remain valid.
It's also possible that two different companies may come out with phones with the same name, in which case if name were your primary key then you would only be able to store information on one of them.

The primary key means that it will be a clustered index - you'll be searching for your name column more than you would be the id column so searches should improve minutely over a non-clustered index. -- https://stackoverflow.com/a/3543719/2724079

I would prefer ID, because name may match like Nokia 500 and HTC 500. You may not add company name in model name. In thise cases you may get multiple. Its better to use "ID" as key in this scenario.
If you prefer not using ID as a additional column then go with combination of company and name as key.

In my opinion using ID column would be better, as if in near by future if you want to add some functionality which includes foreign Key( primary key of a table that appears in other table) concept then Using ID may simply your task and also your effort in various aspect
(If you need to change the name of a phone, and name is the primary key, then any previous references to that phone will immediately stop working because the primary key value is no longer there)

Related

MySQL primary key that I never select

Quite often I encounter situation like this:
table `user_adress`
+----------+-------------+--------------+---------+
|adress_id | user_id | adress_type |adress |
+----------+-------------+--------------+---------+
| 1 | 1 | home |adressXXX|
| 2 | 2 | home |adressXXX|
| 3 | 3 | home |adressXXX|
| 4 | 1 | work |adressXXX|
| 5 | 2 | work |adressXXX|
| 6 | 1 | second_home |adressXXX|
+----------+-------------+--------------+---------+
If I want to use it, I'm using queries like this:
SELECT `adress` FROM `user_adress` WHERE `user_id`=1;
Seems quite normal, but the thing is, that I use "useless" adress_id column, that has no other purpouse but to be an primary key with autoincrement just for the sake of having an primary key in MySQL table. I never use or need this number. So I figured out that I should not use primary key in my table at all, remove totally adress_id, and set INDEX (without unique) at user_id column. That seems to be good - or am I wrong?
I have some doubts, because as much as I'm reading, everywhere I see advices, that every table should, or even need to have primary key. But why? Perhaps my database is badly designed if I allowed this to happen, but looking on my extreamly simple example table - I can't imagine how this could be the case in every situation, especially in such simple cases. I deffinetly missunderstanded some simple, basic rules about creating tables and properly indexing them - where is the hole in my toughts?
Purely based on your table structure, I would say that your primary key is incorrect.
Instead, it looks like your primary should be:
PRIMARY KEY (user_id, address_type)
You are correct that every table should have a primary key ideally, but primary keys can be over multiple fields.
It is still sometimes easier to have a simple auto-incrementing id as your primary key. The Innodb storage engine will actually do this secretly in an invisible field.
Maybe in your limited example it's not needed, but in a lot of real-world cases it can just make it easier to work with the data. In that sense I would say that having an artificial auto-incrementing primary key is not a best practice from an academic standpoint, but it can be good idea from a 'real world, operational, and MySQL admin' perspective.
There's also ORM systems out there that simply require this (bad as that is).
As is evident in your data the primary key allow the access directly to a single row without any problem or ambiguity .. (expecially for delete or updated)
this is specifically the purpose of a primary key ..
di the fact you could need join this table to others table by user_id
and index (not unique ) on user_id
create index myidx on mytable(user_id)
is really useful for faster join allow a direct access only at the rows related to a single user_id
It's true that a relational database table needs a primary key.
But it all comes down to the definition of a primary key. A primary key is NOT necessarily a single integer column that auto-increments.
A primary key is any column or set of multiple columns that can uniquely identify every row. In your case, the combination of user_id and address_type can do this (as Evert posted already).
So if you make your table like this:
CREATE TABLE user_address (
user_id INT NOT NULL,
address_type varchar(10) NOT NULL,
address TEXT NOT NULL,
PRIMARY KEY (user_id, address_type)
);
Then you can update or delete one specific row at a time like this:
UPDATE user_address SET ...
WHERE user_id = ? AND address_type = ?;
Some people feel that it's more convenient to enforce a convention that every table should have a single integer column as its primary key. They even may insist that the column must be called id for the sake of consistency.
There's some advantage in consistency, but on the other hand, it's kind of brainless to insist on that convention even when it's not helpful.

How to use MySQL indexes

I tried to create an index on MySQL using this query
CREATE TABLE test (id INT, age INT, INDEX(id,age));
DESCRIBE test; gives this:
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | YES | MUL | NULL | |
| age | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
When i tried to found why just the id was indexed i found 2 more things. That CREATE INDEX query requeires a name for the index and also that there is a USE INDEX () statement.
Now my questions:
Is the first query wrong or did I indexed both the id and the age like a pair and that's why just ID shows to be indexed?
Can I create indexes without providing a name, as I did in the first query (or when setting a column PRIMARY KEY)?
Should I add USE INDEX everytime I want to use the index? If yes, are there situations when the index is used by default (for example, when creating an index without a name, if possible)?
Your create table query with index - is ok, you can check it by running command
SHOW INDEX FROM test you'll see your index.
In general, it's good practice to create an index with own name (even you can omit it like in your query).
And USE INDEX - it's query performance optimization keyword which is just a suggestion which key mysql can use (you mush use it only if you clearly understand what are you doing, you must not use it for everyone query).
Use SHOW CREATE TABLE; it is more descriptive than DESCRIBE !
The DESCRIBE that you presented disagrees with the existence of INDEX(id,age).
Normally, id is the PRIMARY KEY of a table. You have broken with tradition; please explain what your intent is.
Do not use USE INDEX or FORCE INDEX -- it may help 'today', but is likely to hurt 'tomorrow'. Let the Optimizer decide which (if any) index to use.
We can't critique a schema without knowing what SELECTs you will be using against it.
Every table should have a PRIMARY KEY. Note: A PK is, by definition (in MySQL) both UNIQUE and INDEX.
There is almost no use for the name of an index. If you don't name an index, a name will be generated. A name is necessary when DROPping the index.

Copying related tables, without the primary key but preserving the foreign key relationship

I have a badly designed database in hands. It has some tables with are related to each other by fields that were supposed to be foreign keys. For example, if they were to tables, each of them have a primary key, and the second contains the a column which was supposed to be a foreign key, but it is just a filed manually controlled to maintain the relationship.
My problem is finding a way to copy those tables to a second database, which have the same tables, with its own entries.
I tough about a select statement, excluding the primary key, and putting NULL in the first column(the primary key). By doing so, I could dump the records into a CVS and send it to the second DB, which would use automatic increment for the primary key. However, this would be a problem for the second table, as I would not know the new keys.
| Table A | | Table B |
| keyA | | keyB |
| fields | | keyA |

PRIMARY and FOREIGN key in one field

I have 3 tables: users, pages and users_pages
Users Table
+----+------+-----
| id | name | ...
+----+------+-----
Pages Table
+----+------+-----
| id | name | ...
+----+------+-----
users_pages table, which says, which user is admin of which page.
+---------+---------+
| user_id | page_id |
+---------+---------+
| 1 | 1 | // means, user 1 is admin of page 1
+---------+---------+
in users_pages table, combination of user_id and page_id is a compound key ( primary key )
Is it possible to define user_id and page_id as foreign key while they both together are primary key?
Yes, Absolutely. You havn't mentioned which relational database you are using, but this is common practice, and allowable in all relational databases i know of.
My attempt at an additional explanation:-
Primary and foreign keys are more like 'theoretical' things rather than hard physical things. When looking at the nuts and bolts, I find it useful to think of only indexes and contraints, not of 'keys' as such
Thinking this way a 'primary key' is actually a combination of two separate things :-
A unique contraint. This checks for and refuses any attempts to
create duplicates.
An index based on the field. This just makes
it much faster to retrieve the record if you use that field to look
it up (select * from table where pkey = 'x')
A 'foreign key' in practice is just a contraint, not much different from the unique key contraint. It checks the records exist in the other table, and refuses any attempts to create records with no corresponding entries in the referred to table.
There is no reason why you cant have multiple contraints on the same field (that it is both unique and exists in another table), and whatever indexes is on the table in no way prevents you from adding any contraint you like. Therefore there is no problem having the same field as part of a primary key and it also have a foreign key contraint.

How to use foreign keys with PHP

So I understand how to create foreign keys and I know what is the purpose of the FK. But I have a problem in understanding How to use them. I asked a question regarding Foreign keys HERE(Click link)
Here is what I made:
CREATE TABLE user(
id INT(11) NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(20) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE items(
i_id INT(11) NOT NULL AUTO_INCREMENT,
name TINYTEXT NOT NULL,
price DECIMAL(8,2) NOT NULL,
PRIMARY KEY (i_id)
);
CREATE TABLE user_purchase(
i_id INT(11) NOT NULL,
name TINYTEXT NOT NULL,
id INT(11) NOT NULL,
FOREIGN KEY (i_id) REFERENCES items(i_id),
FOREIGN KEY (name) REFERENCES items(name),
FOREIGN KEY (id) REFERENCES user(id)
);
Now my question is how do I make the most out of this using PHP? From the link above, people have suggested that it's good to use only one foreign key in the user_purchase table, but what if I want several columns? Why don't we use several foreign keys for different columns of the same table?
I am using mysql and php. I would appreciate it if you could show some examples of how you use PHP with the tables which have foreign keys to get get information using MYSQL commands. I really need a thorough explanation.
I also need to understand the terms Normalization and Denormalization. I would appreciate if you could give some links which explain these terms in great detail with examples or if you have any suggestion for some great books for beginners in database design, implementation, etc, I would really appreciate.
Thanks a lot.
Foreign key columns/constraints disambiguation
So I understand how to create foreign keys and I know what is the
purpose of the FK. But I have a problem in understanding How to use
them.
Assuming you are referring to the foreign key constraints, the short answer would be you just don't use them.
And here comes the long one:
We are accustomed to refer to columns being foreign keys to other tables. Especially during the normalization process, phrases like "user_purchase.i_id is a foreign key to the items table" would be very common. While that's a perfectly valid way to describe the relationship, it can get a little fuzzy when we reach the implementation phase.
Suppose you have created your tables without the FOREIGN KEY clauses:
CREATE TABLE user(
id INT(11) NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(20) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE items(
i_id INT(11) NOT NULL AUTO_INCREMENT,
name TINYTEXT NOT NULL,
price DECIMAL(8,2) NOT NULL,
PRIMARY KEY (i_id)
);
CREATE TABLE user_purchase(
i_id INT(11) NOT NULL,
name TINYTEXT NOT NULL,
id INT(11) NOT NULL,
);
Notice that, relation-wise, the foreign key columns are still implemented. There's a column that references the user table (id) and another one that references the items table (i_id) -- let's put the name column aside for a moment. Consider the following data:
user user_purchase items
| id username | | id i_id | | i_id name price |
| 23 john | | 55 10 | | 10 chocolate bar 3.42 |
| 55 mary | | 70 10 | | 33 mobile phone 82.11 |
| 70 fred | | 70 33 | | 54 toothpaste 8.67 |
| 55 10 | | 26 toy car 6.00 |
| 70 26 |
The relation is there. It is implemented by means of the user_purchase table, which holds information as to who bought what. If we were to query the database for a relevant report, we would do:
select * from user_purchase p
join user u on (p.id=u.id)
join items i on (p.i_id=i.i_id)
And that's how we use the relation and the foreign key columns involved.
Now, what if we do:
insert into user_purchase (id,i_id) values (23,99)
Apparently, this is an invalid entry. Although there is a user with id=23, there's no item with i_id=99. The RDBMS would allow that to happen, because it doesn't know any better. Yet.
That's where foreign key constraints come into play. By specifying FOREIGN KEY (i_id) REFERENCES items(i_id) in the user_purchase table definition, we essentially give the RDBMS a rule to follow: entries with i_id values that are not contained in the items.i_id column are not acceptable. In other words, while a foreign key column implements the reference, a foreign key constraint enforces the referential integrity.
Note, however, that the above select wouldn't change, just because you defined a FK constraint. Thus, you don't use FK constraints, the RDBMS does, in order to protect your data.
Redundancies
...what if I want several columns? Why don't we use several foreign
keys for different columns of the same table?
Ask yourself: Why would you want that? If the two foreign keys are to serve the same purpose, the redundancy will eventually get you in trouble. Consider the following data:
user_purchase items
| id i_id name | | i_id name price |
| 55 10 chocolate bar | | 10 chocolate bar 3.42 |
| 70 10 chocolate bar | | 33 mobile phone 82.11 |
| 70 33 mobile phone | | 54 toothpaste 8.67 |
| 55 10 toothpaste | | 26 toy car 6.00 |
| 70 26 toy car |
What's wrong with this picture? Did user 55 buy two chocolate bars, or a chocolate bar and a toothpaste? This kind of ambiguity can lead to a lot of effort to keep data in-sync, which would be unnecessary if we just kept one of the foreign keys. In fact, why not drop the name column altogether, since it is implied by the relation.
Of course, we could resolve this by implementing a composite foreign key, by setting PRIMARY KEY(i_id,name) for the items table (or defining an extra UNIQUE(i_id,name) index, it doesn't realy matter) and then setting a FOREIGN KEY(i_id,name) REFERENCES items(i_id,name). This way, only (i_id,name) couples that exist in the items table would be valid for user_purchases. Apart from the fact that you would still have one foreign key, this approach is totally unnecessary, provided that the i_id column is already enough to identify an item (can't say the same for the name column...).
However, there's no rule against using multiple foreign keys to a table. In fact, there are circumstances that demand such an approach. Consider a person(id,name) table and a parent(person,father,mother) one, with the following data:
person parent
| id name | | person father mother |
| 14 John | | 21 14 59 |
| 43 Jane | | 14 76 43 |
| 21 Mike |
| 76 Frank |
| 59 Mary |
Obviously, all three columns of the parent table are foreign keys to person. Not for the same relation, though, but for three different ones: Since a person's parents are persons too, the two corresponding columns must reference the same table person does. Note, however, that the three fields not only can but also have to refer different persons in the same parent row, since noone is his own parent and noone's father is his mother as well.
Foreign keys are used in joins. For instance, if you want to know the usernames that purchased a particular item, you would write:
select u.username
from items i
join user_purchase up on i.i_id = up.i_id
join user u on u.id = up.id
where i.name = "Some product name"
They may also be used by the database engine itself. It can detect if you create a row in user_purchase whose id or i_id column doesn't match anything in the referenced column in the other table.
You should not replicate the name column in the user_purchase table. The name is just an attribute of the item, it's not specific to any particular purchase. If you need to get the name of the item that was purchased, join with the items table.
Instead of reading so many links, just try to implement this in any simple project. I'm just explaining how we gonna use the above tables.
Suppose you 3 users in user table and 5 items in items table.
user table
id | username | password
1 abc 123
2 def 456
3 qwe 987
items table
i_id | name | price
1 item 1 6
2 item 2 8
3 item 3 11
4 item 4 3
5 item 5 14
your user_purchase table look like this
CREATE TABLE user_purchase(
i_id INT(11) NOT NULL,
id INT(11) NOT NULL,
FOREIGN KEY (i_id) REFERENCES items(i_id),
FOREIGN KEY (id) REFERENCES user(id)
);
There is no need of item name again in this table. So I have removed.
i_id | id
1 1
1 2
2 2
3 3
In the above table we will get, user 1 has purchased item 1, user 2 has purchased item 1,item 2 and user 3 has purchased item 3.
This is how normalization works. You can use MySQL JOIN for getting user name and item details
SELECT B.user_name,C.name AS item_name,C.price
FROM user_purchase A
JOIN user B ON A.id = B.id
JOIN items C ON A.i_id = C.i_id
Here is foreign key use to join
A.id = B.id
A.i_id = C.i_id
You treet tables with foreign keys in php the same way, as if they had no foreign keys. Foreign keys are defined in the database and have (almost) nothing to do with php. The only thing you have to do in php is reacting to potential errors that can be returned by sql queries, which brake the foreign key constraint (typically DELETE queries).
And for your database schema, you should drop column "name" from "table user_purchase". It is redundat.
Just looking at the normalization/de-normalization point:
Normalization is a process of trying to remove redundancy in your database - in your example the name field in user_purchase is redundant - I can find out the name of the item by looking it up in the items table using i_id.
So if we were to look at normalizing user_purchase we'd probably remove the name field and use a JOIN to retrieve that when we needed it. This would, of course, also mean we don't need the second FOREIGN KEY reference to items.
De-normalization is basically going the opposite way - adding redundancy - usually done for performance reasons.
However, in your example you might also consider de-normalization for business reasons too. For example you might decide it is important to store the product name as it was when the user actually purchased it (rather than what it's called now) - just in case you need to be able to re-print an invoice for example. However even in this case you wouldn't want the FOREIGN KEY back to items (as it would "break" if the product was re-named).