In MySQL, is it possible to have a column in two different tables that auto-increment? Example: table1 has a column of 'secondaryid' and table2 also has a column of 'secondaryid'. Is it possible to have table1.secondaryid and table2.secondaryid hold the same information? Like table1.secondaryid could hold values 1, 2, 4, 6, 7, 8, etc and table2.secondaryid could hold values 3, 5, 9, 10? The reason for this is twofold: 1) the two tables will be referenced in a separate table of 'likes' (similar to users liking a page on facebook) and 2) the data in table2 is a subset of table1 using a primary key. So the information housed in table2 is dependent on table1 as they are the topics of different categories. (categories being table1 and topics being table2). Is it possible to do something described above or is there some other structural work around that im not aware of?
It seems you want to differentiate categories and topics in two separate tables, but have the ids of both of them be referenced in another table likes to facilitate users liking either a category or a topic.
What you can do is create a super-entity table with subtypes categories and topics. The auto-incremented key would be generated in the super-entity table and inserted into only one of the two subtype tables (based on whether it's a category or a topic).
The subtype tables reference this super-entity via the auto-incremented field in a 1:1 relationship.
This way, you can simply link the super-entity table to the likes table just based on one column (which can represent either a category or a topic), and no id in the subtype tables will be present in both.
Here is a simplified example of how you can model this out:
This model would allow you to maintain the relationship between categories and topics, but having both entities generalized in the superentity table.
Another advantage to this model is you can abstract out common fields in the subtype tables into the superentity table. Say for example that categories and topics both contained the fields title and url: you could put these fields in the superentity table because they are common attributes of its subtypes. Only put fields which are specific to the subtype tables IN the subtype tables.
If you just want the ID's in the two tables to be different you can initially set table2's AUTO_INCREMENT to some big number.
ALTER TABLE `table2` AUTO_INCREMENT=1000000000;
You can't have an auto_increment value shared between tables, but you can make it appear that it is:
set ##auto_increment_increment=2; // change autoinrement to increase by 2
create table evens (
id int auto_increment primary key
);
alter table evens auto_increment = 0;
create table odds (
id int auto_increment primary key
);
alter table odds auto_increment = 1;
The downside to this is that you're changing a global setting, so ALL auto_inc fields will now be growing by 2 instead of 1.
It sounds like you want a MySQL equivalent of sequences, which can be found in DBMS's like PosgreSQL. There are a few known recipes for this, most of which involve creating table(s) that track the name of the sequence and an integer field that keeps the current value. This approach allows you to query the table that contains the sequence and use that on one or more tables, if necessary.
There's a post here that has an interesting approach on this problem. I have also seen this approach used in the DB PEAR module that's now obsolete.
You need to set the other table's increment value manually either by the client or inside mysql via an sql function:
ALTER TABLE users AUTO_INCREMENT = 3
So after inserting into table1 you get back the last auto increment then modify the other table's auto increment field by that.
I'm confused by your question. If table 2 is a subset of table 3, why would you have it share the primary key values. Do you mean that the categories are split between table 2 and table 3?
If so, I would question the design choice of putting them into separate tables. It sounds like you have one of two different situations. The first is that you have a "category" entity that comes in two flavors. In this case, you should have a single category table, perhaps with a type column that specifies the type of category.
The second is that your users can "like" things that are different. In this case, the "user likes" table should have a separate foreign key for each object. You could pull off a trick using a composite foreign key, where you have the type of object and a regular numeric id afterwards. So, the like table would have "type" and "id". The person table would have a column filled with "PERSON" and another with the numeric id. And the join would say "on a.type = b.type and a.id = b.id". (Or the part on the "type" could be implicit, in the choice of the table).
You could do it with triggers:
-- see http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id
CREATE TABLE sequence (id INT NOT NULL);
INSERT INTO sequence VALUES (0);
CREATE TABLE table1 (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
secondardid INT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (id)
);
CREATE TABLE table2 (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
secondardid INT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (id)
);
DROP TRIGGER IF EXISTS table1_before_insert;
DROP TRIGGER IF EXISTS table2_before_insert;
DELIMITER //
CREATE
TRIGGER table1_before_insert
BEFORE INSERT ON
table1
FOR EACH ROW
BEGIN
UPDATE sequence SET id=LAST_INSERT_ID(id+1);
NEW.secondardid = LAST_INSERT_ID();
END;
//
CREATE
TRIGGER table2_before_insert
BEFORE INSERT ON
table2
FOR EACH ROW
BEGIN
UPDATE sequence SET id=LAST_INSERT_ID(id+1);
NEW.secondardid = LAST_INSERT_ID();
END;
//
Related
i have two tables(innodb) in MYSQL data base both share a similar column the account_no column i want to keep both columns as integers and still keep both free from collusion when inserting data only.
there are 13 instances of this same question on stackoverflow i have read all. but in all, the recommended solutions where:
1) using GUID :this is good but am trying to keep the numbers short and easy for the users to remember.
2) using sequence :i do not fully understand how to do this but am thinking it involves making a third table that has an auto_increment and getting my values for the the two major tables from it.
3) using IDENTITY (1, 10) [1,11,21...] for the first table and the second using IDENTITY (2, 10) [2,12,22...] this works fine but in the long term might not be such a good idea.
4) using php function uniqid(,TRUE) :not going to work its not completely collision free and the columns in my case have to be integers.
5) using php function mt_rand(0,10): might work but i still have to check for collisions before inserting data.
if there is no smarter way to archive my goal i would stick with using the adjusted IDENTITY (1, 10) and (2, 10).
i know this question is a bit dumb seeing all the options i have available but the most recent answer on a similar topic was in 2012 there might have been some improvements in the MYSQL system that i do not know about yet.
also am using php language to insert the data thanks.
Basically, you are saying that you have two flavors of an entity. My first recommendation is to try to put them in a single table. There are three methods:
If most columns overlap, just put all the columns in a single table (accounts).
If one entity has more columns, put the common columns in one table and have a second table for the wider entity.
If only some columns overlap, put those in a single table and have a separate table for each subentity.
Let met assume the third situation for the moment.
You want to define something like:
create table accounts (
AccountId int auto_increment primary key,
. . . -- you can still have common columns here
);
create table subaccount_1 (
AccountId int primary key,
constraint foreign key (AccountId) references accounts(AccountId),
. . .
);
create table subaccount_2 (
AccountId int primary key,
constraint foreign key (AccountId) references accounts(AccountId),
. . .
);
Then, you want an insert trigger on each sub-account table. This trigger does the following on insert:
inserts a row into accounts
captures the new accountId
uses that for the insert into the subaccount table
You probably also want something on accounts that prevents inserts into that table, except through the subaccount tables.
A big thank you to Gordon Linoff for his answer i want to fully explain how i solved the problem using his answer to help others understand better.
original tables:
Table A (account_no, fist_name, last_name)
Table B (account_no, likes, dislikes)
problem: need account_no to auto_increment across both tables and be unique across both tables and remain a medium positive integer (see original question).
i had to make an extra Table_C to which will hold all the inserted data at first, auto_increment it and checks for collisions through the use of primary_key
CREATE TABLE Table_C (
account_no int NOT NULL AUTO_INCREMENT,
fist_name varchar(50),
last_name varchar(50),
likes varchar(50),
dislikes varchar(50),
which_table varchar(1),
PRIMARY KEY (account_no)
);
Then i changed MySQL INSERT statement to insert to Table_C and added an extra column which_table to say which table the data being inserted belong to and Table_C on insert of data performs auto_increment and checks collision then reinsert the data to the desired table through the use of triggers like so:
CREATE TRIGGER `sort_tables` AFTER INSERT ON `Table_C` FOR EACH ROW
BEGIN
IF new.which_table = 'A' THEN
INSERT INTO Table_A
VALUES (new.acc_no, new.first_name, new.last_name);
ELSEIF new.which_table = 'B' THEN
INSERT INTO Table_B
VALUES (new.acc_no, new.likes, new.dislikes);
END IF;
END
I have seen a question on this forum that I can relate with, but I can't apply the answers to my question.
Here it goes:
I have a memberlist table (id, name, number) I'll just make the columns short.
Next, I have an events table (id, eventName, description)
Now,
1. each member in the memberlist can join events as many as he wants.
2. each events in the events table can have members without limits (okay, say 1k members, like that or whatever).
What I have now is an event table that has a column named: "joiners" which will contain the id of a certain joiner/member. But I believe I'm wrong because how can a certain event handles many joiner's id?
I would rename memberlist into members to make your table naming more consistent. Or events into eventlist. Which ever you like more.
Then you want to define a many to many relation between members and events. This is done through an intermediate table which will reference both:
create table eventmembers (
id int unsigned not null primary_key auto_increment,
member_id int unsigned not null references members(id),
event_id int unsigned not null references events(id)
)
I'm assuming that on your memebers and events you already have id fields which are set to be primary keys.
If you want to get all events attended by a specific user you can then do
select events.*
from events
left join eventmembers
on events.id = eventmembers.event_id
where
member_id = ?
and get all the members in an event:
select members.*
from members
left join eventmembers
on members.id = eventmembers.member_id
where
event_id = ?
You'd want a third table called events_memberlist :
events_memberlist
- memberlistId
- eventId
This would allow you to maintain a many-to-many relationship between the two tables.
you need a third table for fun we will call it EventMemberTable, col's:
event id | member
it links the appropiat member to the appropiat event. Keeping your other tables clear of redundant data.
You can achieve this by having a middle table (between members, and events). Middle tables are necessary in situations where a 'many-to-many' relationship between two tables is required.
In the middle table, you will include the primary keys of both tables as foreign keys, on the same row, when a member has joined an event. The foreign keys effectively create the relationship between one member, and one event. The table however, can have thousands of these entries.
I hope that helps.
P.S. Maybe post some syntax next time.
Cheers
When you use a middle table as already mentioned like:
CREATE TABLE event_members (
member_id INT UNSIGNED NOT NULL REFERENCES members(id),
event_id INT UNSIGNED NOT NULL REFERENCES events(id)
)
you should also set up a unique index to prevent multiple entries for the same member/event combination like
ALTER TABLE event_members ADD UNIQUE INDEX uniq_event_members_idx (member_id, event_id);
Otherwise you might end up with loads of duplicates.
I need to store multiple id's in either a field in the table or add another table to store the id's in.
Each member will basically have favourite articles. Each article has an id which is stored when the user clicks on a Add to favourites button.
My question is:
Do I create a field and in this field add the multiple id's or do I create a table to add those id's?
What is the best way to do this?
This is a many-to-many relationship, you need an additional table storing pairs of user_id and article_id (primary keys of user and article tables, respectively).
You should create a new table instead of having comma seperated values in a single column.
Keep your database normalized.
You create a separate table, this is how things work in a relational database. The other solution (comma separated list of ids in one column) will lead to an unmaintainable database. For example, what if you want to know how many times an article was favorited? You cannot write queries on a column like this.
Your table will need to store the user's id and the article's id - these refer to the primary keys of the corresponding tables. For querying, you can either use JOINs or nested SELECT queries.
As lafor already pointed out this is a many-to-many relationship and you'll end up with three tables: user, article, and favorite:
CREATE TABLE user(
id INT NOT NULL,
...
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE article (
id INT NOT NULL,
...
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE favorite (
userID INT NOT NULL,
articleID INT NOT NULL,
FOREIGN KEY (userID) REFERENCES user(id) ON DELETE CASCADE,
FOREIGN KEY (articleID) REFERENCES article(id) ON DELETE CASCADE,
PRIMARY KEY (userID, articleID)
) ENGINE=INNODB;
If you then want to select all user's favorite articles you use a JOIN:
SELECT * FROM favorite f JOIN article a ON f.articleID = a.id WHERE f.userID = ?
If you want to know why you should use this schema, I recommend reading about database normilization. With multiple IDs in a single field you would even violate the first normal form and thus land in a world of pain...
Say I have two tables. One, lets call it typeDB, has for rows consisting of an index, a type name, and a list of IDs for elements in the other table which are of this type. To get the rows from the second table - lets call it dataDB - of type 0, I could then basically do (in sloppy pseudocode):
$list = SELECT list FROM typeDB WHERE index=0
And then I could get the rows from dataDB using:
$array = explode($list)
for (every element of list $i)
$results = SELECT * FROM dataDB WHERE index=$array[$i]
So my question is... is this any faster than just having a type field in dataDB, and then doing:
$results = SELECT * FROM dataDB WHERE type=$type
My thought was that because the first method didn't have to go through the entire database, it would be faster. But I don't really know how the database queries work. Which way do you think would be the most efficient? Thanks.
Put an index on the type column and use your second version, it will be much faster.
Also note that I think you are bit confused by what a database is.. A database is a collection of tables (as well as triggers, stored procedures, views, etc) so naming tables with the name somethingDB is a bit confusing..
When I say index i'm referring to a database index (nothing to do with what looks like a column you had called index).
to create the column and index you use something like this (for mysql)
ALTER TABLE dataDB ADD COLUMN `type` varchar(64)
CREATE INDEX type_index ON dataDB(type)
similar for other DBMS's
As brought up in the comments, you then need to join on the type column.
You can either have a table that has types and an auto increment id and a unique constraint on the type/name field.. Then use the auto increment id as the foreign key, or just make a type table with one column (type) which is the primary key. Either way will work and both have benefits (I would go with an auto increment column as I believe it is more flexible to work with in code).
If you did go with an auto increment column you'd have this:
CREATE TABLE dataType (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(64) UNIQUE
)
ALTER TABLE dataDB ADD COLUMN `type` INT;
ALTER TABLE dataDB ADD CONSTRAINT fk_type FOREIGN KEY (type) REFERENCES dataType(id);
then when you go to query dataDB if you want the type names (as opposed to the integers) you would do a join like this:
SELECT dataDB.list, dataType.name FROM dataDB
INNER JOIN dataType ON dataDB.type=dataType.id
where dataDB.type="$type"
This assumes types are some kind of name and not integers to begin with though, if they were integers all along just make the int value the only column of the dataType table and thus it would be your primary key.
I am starting to learn PHP;
i have two tables in my database:
the Brands List that contains Brand_ID, Brand_Name, and
Brand_Description.
the Product Lines List that contains Line_ID, Line_Name.
i want to create a third table named Offered Products that contains Offer_Id, Brand_ID, Line_Name - how can i manage this using Foreign Keys?
After creating the table, i want to create a php page that will let users to populate the third table by
Selecting a brand from a dropdown list
Selecting a Line Name from a drop down List
Beside it has a button "Add Row" - which when click will display
another row below the first one in order to do number 1 and 2 again
and so on
A save button is also present which when clicked will finally save
the record on my database.
how can i exactlydo this? please help
Creating the table.
Your third table would only need to store Line_ID and Brand_ID and (for whatever reason) you also want Offer_ID.
CREATE TABLE `Offered Products` (
/* define columns */
Offer_ID INT NOT NULL AUTO_INCREMENT,
Brand_ID INT NOT NULL,
Line_ID INT NOT NULL,
/* define primary key */
PRIMARY KEY (Offer_ID)
/* define foreign keys */
FOREIGN KEY Brand_ID (Brand_ID)
REFERENCES `Brands List` (Brand_ID)
FOREIGN KEY Line_ID (Line_ID)
REFERENCES `Lines List` (Line_ID)
);
This assumes that the Lines List table (with a space) and Brand List table have Line_ID and Brand_ID respectively defined as primary keys.
Creating the form.
Design the form with HTML and PHP. Have each list populated from the corresponding table. I'm not going to provide code for this; it should be straight forward.
Inserting into the table.
INSERT INTO `Offered Products` (Brand_ID, Line_ID) VALUES (###, ###)
The ### represents the ID numbers from the HTML form.
Joining the tables.
To obtain information from all of the tables you can join as below.
SELECT * FROM `Offered Products` as op
JOIN `Brand List` as bl ON bl.Brand_ID = op.Brand_ID
JOIN `Line List` as ll on ll.Line_ID = op.Line_ID
Other Notes.
To use foreign keys in MySQL you need to be using the InnoDB engine. Using myisam will not allow foreign keys, but you can still join the tables as demonstrated to achieve a similar result.
Avoid using spaces in your table names if you actually did that.