I was wondering which of following is better design.
I've got these tables
users
ID | NAME
Categories
ID | NAME
Which one is better, this:
users_to_categories
CAT_ID | USER_ID
In this case CAT_ID and USER_ID are primary keys
or one primary key
users_to_categories
ID | CAT_ID | USER_ID
only ID is primary key
I assume that you are trying to create a many-to-many relationship between the two tables with a third table titled Users_to_Categories. If so, then CAT_ID and USER_ID would be foreign key pointers to the primary keys in Users and Categories.
All that being said, I would refer to the answer given in this thread (SQL - many-to-many table primary key). I agree with the answer given here, saying that there is really no advantage to creating a new auto-increment primary key when the combination of the CAT_ID/USER_ID can serve as a primary key itself.
Altought both designs are fine, I recommend go for one single field for key approach.
It's easier for doing queries.
It's also easier when you want to change some details records from a header o parent table to another, just change the parent foreign key.
Related
Here is a gross oversimplification of an intense setup I am working with. table_1 and table_2 both have auto-increment surrogate primary keys as the ID. info is a table that contains information about both table_1 and table_2.
table_1 (id, field)
table_2 (id, field, field)
info ( ???, field)
I am trying to decided if I should make the primary key of info a composite of the IDs from table_1 and table_2. If I were to do this, which of these makes most sense?
( in this example I am combining ID 11209 with ID 437 )
INT(9) 11209437 (i can imagine why this is bad)
VARCHAR (10) 11209-437
DECIMAL (10,4) 11209.437
Or something else?
Would this be fine to use this as the Primary Key on a MYSQL MYISAM DB?
I would use a composite (multi-column) key.
CREATE TABLE INFO (
t1ID INT,
t2ID INT,
PRIMARY KEY (t1ID, t2ID)
)
This way you can have t1ID and t2ID as foreign keys pointing to their respective tables as well.
I would not make the primary key of the "info" table a composite of the two values from other tables.
Others can articulate the reasons better, but it feels wrong to have a column that is really made up of two pieces of information. What if you want to sort on the ID from the second table for some reason? What if you want to count the number of times a value from either table is present?
I would always keep these as two distinct columns. You could use a two-column primay key in mysql ...PRIMARY KEY(id_a, id_b)... but I prefer using a two-column unique index, and having an auto-increment primary key field.
the syntax is CONSTRAINT constraint_name PRIMARY KEY(col1,col2,col3) for example ::
CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName)
the above example will work if you are writting it while you are creating the table for example ::
CREATE TABLE person (
P_Id int ,
............,
............,
CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName)
);
to add this constraint to an existing table you need to follow the following syntax
ALTER TABLE table_name ADD CONSTRAINT constraint_name PRIMARY KEY (P_Id,LastName)
Suppose you have already created a table now you can use this query to make composite primary key
alter table employee add primary key(emp_id,emp_name);
Aside from personal design preferences, there are cases where one wants to make use of composite primary keys. Tables may have two or more fields that provide a unique combination, and not necessarily by way of foreign keys.
As an example, each US state has a set of unique Congressional districts. While many states may individually have a CD-5, there will never be more than one CD-5 in any of the 50 states, and vice versa. Therefore, creating an autonumber field for Massachusetts CD-5 would be redundant.
If the database drives a dynamic web page, writing code to query on a two-field combination could be much simpler than extracting/resubmitting an autonumbered key.
So while I'm not answering the original question, I certainly appreciate Adam's direct answer.
Composite primary keys are what you want where you want to create a many to many relationship with a fact table. For example, you might have a holiday rental package that includes a number of properties in it. On the other hand, the property could also be available as a part of a number of rental packages, either on its own or with other properties. In this scenario, you establish the relationship between the property and the rental package with a property/package fact table. The association between a property and a package will be unique, you will only ever join using property_id with the property table and/or package_id with the package table. Each relationship is unique and an auto_increment key is redundant as it won't feature in any other table. Hence defining the composite key is the answer.
CREATE TABLE `mom`.`sec_subsection` (
`idsec_sub` INT(11) NOT NULL ,
`idSubSections` INT(11) NOT NULL ,
PRIMARY KEY (`idsec_sub`, `idSubSections`)
);
#AlexCuse I wanted to add this as comment to your answer but gave up after making multiple failed attempt to add newlines in comments.
That said, t1ID is unique in table_1 but that doesn't makes it unique in INFO table as well.
For example:
Table_1 has:
Id Field
1 A
2 B
Table_2 has:
Id Field
1 X
2 Y
INFO then can have:
t1ID t2ID field
1 1 some
1 2 data
2 1 in-each
2 2 row
So in INFO table to uniquely identify a row you need both t1ID and t2ID
let's say, I have a simple database with 3 tables = posts, categories and post_category (which is pivot table).
posts - ID | title | body | created_at/updated_at
categories - ID | name | created_at/updated_at
post_category - post_id | category_id
The primary key is an ID, but I have not specified a foreign key (in posts). Should I specify the foreign key (category_id) as a column in my posts table, or is it okay to use pivot table (post_category) where I already specified the relationship between those 2 tables?
Thanks in advance!
SQL does not require foreign keys to be explicitly declared, particularly with respect to querying tables. Foreign keys enforce relational integrity. That is, they ensure that tables that should refer to each other actually do refer to each other.
That said, MySQL differs from most databases by actually doing something with a foreign key declaration: MySQL builds a secondary index. This index can be quite handy for queries by improving performance.
However, nothing is required about a foreign key relationship.
Imagine we have three tables in a MySQL database:
posts
categories
category_post
There is a one-to-many relationship between posts and categories so that a single post may have many categories.
The category_post table is the pivot table between categories and posts and has the following columns:
id (primary key, auto-incrementing, big integer)
category_id
post_id
Let's also imagine that we have 1,000,000 rows in our category_post table.
My question is:
Is there any performance benefit to having the id column in the category_post table or does it just take up extra space?
Posts and categories is probably many-to-many, not one-to-many.
A many-to-many relationship table is best done something like
CREATE TABLE a_b (
a_id ... NOT NULL,
b_id ... NOT NULL,
PRIMARY KEY (a_id, b_id),
INDEX(b_id, a_id) -- include this if you need to go both directions
) ENGINE = InnoDB;
With that, you automatically get "clustered" lookups both directions, and you avoid the unnecessary artificial id for the table.
(By the way, N.B., an implicit PK is 6 bytes, not 8. There is a lengthy post by Jeremy Cole on the topic.)
A one-to-many relationship does not need this extra table. Instead, have one id inside the other table. For example, a City table will have the id for the Country in it.
Having category_id and post_id as a compound primary key will have better performance than having an extra id as a primary key. This is because making it a primary key will also create an index on it automatically. If you really want an extra Id column you can improve performance by manually defining an index on category_id and post_id. There is no benefit of having an extra key column though and this is generally a bad practice.
not having id is good, but when you care about ordering by the pivot table you will need to have id or timestamp in pivot table
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.
I have a movie table and want to store alternative titles. I'll be storing the alternative titles/aliases in another table. I'm not sure what is the best primary key to use though.
I will have a movie_id INT field, and an alias varchar(255) field. Should the primary key be on both fields (since one movie can have more than one alias)? Should I add another field for the primary key instead, for example alias_id that just auto increments, but this serves no purpose otherwise. Or does this table need a primary key? Maybe it should just have a unique index on the alias and no primary key is needed?
Your movie_id could be your only PK and auto-incrementing. Then make a FK movie_id in your alternative alias table to match the alt. name with its original title.
movie_id | Title
--------------------
1 | "Jaws"
2 | "Star Trek"
3 | "Matrix 3"
movie_id | Alt_Title
------------------------
1 | "Death Shark"
1 | "Tales of the Deep"
3 | "Neo is Uber"
1 | "Another Jaws Title"
When you make an insert into the alt name table, you will have to make a join on the original title, and pull its movie_id to insert with.
put primary key on id fields in all cases, because the data storage is efficient and match-search operations is quick. if u want to enforce uniqueness use a unique index on the field(s) u want except primary key. primary keys are by default necessary and unique.
To answer your question directly, you want to make the movie_id be a foreign key in your alt_title table. Then the simplest thing is probably to create a separate alt_title_id field to be the primary key of the alt_title table. I wouldn't make the title the primary key, because thats awfully long and cumbersome to make a good key.
I'm not sure what you're doing with this data, but my impulse would be to create a single table to hold both primary and alternate titles, and then just have a flag to identify the primary. Assuming you have a bunch of other data about each movie, pull the title out of the basic movie record into a separate table. If you put them in one table, then if you want to search by either primary or alternate title, you just say
select whatever
from movie_title
join movie using (movie_id)
where title='Java Forever'
If you want to search by just primary title for some reason, fine, you write
select whatever
from movie_title
join movie using (movie_id)
where title='Java Forever' and primary=true
With two tables, if you want to search by primary title, sure, it's easy. But if you want to search by primary or alternate, you need a union, which is slow and painful. If the query is complex, joining on several other tables or pulling out a bunch of fields, all that extra complexity has to be written twice, in each half of the join.