create relationship between tables - mysql

I have tables for dogs, cats , horses containing rows of information about them , i want to create a table photo where info about photos of each can be created and so want to establish one-to-many relation b/w name attribute of each table with table photo . I am using name attribute in each table and it is set to unique but not primary , i want a way to join them so that for each name if there are multiple entries in photo table they could be shown.

I strongly recommend you use an int primary key rather than name for linking your tables.
If you need to change the name of any animal, the links effectively break.
Simple example:
CREATE TABLE `animals` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(32) DEFAULT NULL,
`species` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `images` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`animal_id` int(10) NOT NULL,
`image_url` varchar(1024) DEFAULT NULL,
PRIMARY KEY (`id`)
);
You also might do well to create a third table for species and make that a link rather than a text field.
The idea is ease of management and future-proofing.
A query to get data for a specific animal and all its images would be like this:
SELECT a.name, a.species, i.image_url
FROM animals a
LEFT JOIN images i ON (i.animal_id = a.id)
WHERE a.id = 123;
name species image_url
----- ----- -----
Fido dog images/fido1.jpg
Fido dog images/fido2.jpg
Other queries are possible, but this scheme allows you to have animals with the same name and they won't conflict.

Related

MySQL getting contents from one table that is related by a foreign key from another table

I have two tables:
CREATE TABLE users(
userID int primary key not null auto_increment,
username varchar(16),
passcode varchar(16),
email varchar(50) not null
);
CREATE TABLE favorites(
userID int not null,
favID1 varchar(50) not null,
favID2 varchar(50) not null,
favID3 varchar(50) not null,
favID4 varchar(50) not null,
favID5 varchar(50) not null,
favID6 varchar(50) not null,
favID7 varchar(50) not null,
favID8 varchar(50) not null,
favID9 varchar(50) not null,
favID10 varchar(50) not null,
favID11 varchar(50) not null,
favID12 varchar(50) not null,
FOREIGN KEY fk1(userID) REFERENCES users(userID)
);
And I would like to get the contents of the favorites table with just the username from the users table, what would the statement for it look like? I'm fairly new to SQL and databases, so apologies if this is trivial. Every other resource I've looked at doesn't seem to relate to what I want to do.
Your database design has some problems. Instead of maintaining separate columns for each favorite, you should modify the favorites table such that a single record stores one, and only one, user-favorite relationship:
CREATE TABLE favorites (
userID int not null,
favID varchar(50) not null,
FOREIGN KEY fk1(userID) REFERENCES users(userID)
);
Now, if you want to report the favorite IDs for a given user, you need only use a basic join, e.g.
SELECT
u.userID,
u.username,
GROUP_CONCAT(f.favID ORDER BY f.favID) AS favIDs
FROM users u
LEFT JOIN favorites f
ON u.userID = f.userID
GROUP BY
u.userID,
u.username;
Perhaps the biggest problem with your current design of the favorites table is that it only admits up to 12 favorite IDs. Should your system ever have the need to support more than that, the table itself would have to be modified, i.e. you would need a DDL change. With my suggested design, you would only need to add more records/data, which is a DML change.

Table localization - One column for a table

I have got only one column for a table when i create two localized tables. Code as bellow.
-- Month
CREATE TABLE `month` (
`id` INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
);
-- Month Localized
CREATE TABLE `month_loc` (
`month_id' INT NOT NULL,
`name` VARCHAR(200) NOT NULL,
`description` VARCHAR(500) NOT NULL,
`lang_id` INT NOT NULL
);
month_loc.month_id is the foreign key.
month table holds only the primary key. Other all fields should be localized. Is this table structure correct ?
Thanks.
If correct implies a certain degree of normalization, and the content of your columns name and description vary per month_id, lang_id (which would be the combined primary key of month_loc), then yes, your design has reached the 3rd grade of normlization.

What is the best way to have a varchar primary key column with an auto-increment?

I would like to create some tables in MySQL. One table would be for users, one for topics, one for comments, and so on.
I need each table to have its own ID column in the following format:
USERS table: ID column
Values:
USR00001
USR00002
USR00003
..
..
USR99999
where as topics table would have IDs like:
TPC00001
TPC00002
TPC00003
similarly, the comments table would have the following IDs:
CMT00001
CMT00002
I tried to use UNIQUE key but did not work: (inspired by this answer)
CREATE TABLE `users` (
`ID` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT ,
`firstname` VARCHAR(100) NOT NULL ,
`lastname` VARCHAR(100) NOT NULL ,
`email` VARCHAR(100) NOT NULL ,
PRIMARY KEY (`ID`)
UNIQUE KEY ( 'USR' + `ID`)
);
Can it be done using triggers (Before Insert) maybe?
Please note that I don't want to handle the insertion of the primary keys on the application level. I would prefer the database engine to handle all the work for that.

Correct database? Does it need altering?

I'm creating a page where I want users to be able to book a seat for an event.
1 user can only book 1 seat
users have no seat selected upon login, first after buying into a spot
Need to able to clear seats table, without loosing anything from user-table (except of course the assigned seats.)
I've created two tables, and since I'm pretty new to mySQL, I wanted to check if this was done correctly:
members-table:
user_id int(8) Not null auto_increment
user_name varchar(30) Not null
user_pass varchar(255) Not null
seat_ID smallint(6) Yes NULL
seats-table
seat_ID smallint(6) No auto_increment
user_id smallint(6) Yes NULL
seat_status tinyint(4) Yes NULL
seat_status tinyint(4) Yes NULL
I've created 2 FK-refs:
ALTER TABLE seats
ADD CONSTRAINT FK_seats
FOREIGN KEY (user_id) REFERENCES members(user_id)
ON UPDATE CASCADE
ON DELETE CASCADE;
ALTER TABLE seats
ADD CONSTRAINT FK_seats
FOREIGN KEY (seat_ID) REFERENCES members(seat_ID)
ON UPDATE CASCADE
ON DELETE CASCADE;
Am I on the right track? Will I be able to progress to a decent final product with this setup? suggestions/improvements? I don't want to start all over in a couple of weeks because the database structure is of poor quality.
First of all I don't see why you're using a second table if any user can only hold one seat at any given time, secondly user_id in seats-table should be the same size as user_id in members table namely int(8), otherwise you won't be able to seat users after a while, third issue is the duplication of seat_status, I suppose that was a mistake or you had another name for it.
In my opinion a better idea is to use a single table if it's a 1->1 mapping and define it as
CREATE TABLE `members-table` (
user_id int(8) not null auto_increment,
user_name varchar(30) not null,
user_pass varchar(255) not null,
seat -- your type choice, should be nullable if not seated
);
Clearing the seats with this config would be as simple as
UPDATE `members-table` SET `seat` = NULL;
CREATE TABLE `seats` (
id int(4) unsigned not null auto_increment primary key,
row int(2) unsigned not null,
col int(2) unsigned not null,
UNIQUE(row, col)
) ENGINE InnoDB;
CREATE TABLE `members` (
user_id int(8) not null auto_increment primary key,
user_name varchar(30) not null,
user_pass varchar(255) not null,
seat int(4) unsigned null,
FOREIGN KEY(seat) references seats(id) on delete set null on update restrict,
UNIQUE(seat)
) ENGINE InnoDB;
You will have to populate the seats database with all available rows and columns, use null on id when inserting to use the auto_increment feature!
Check if a seat is taken
SELECT COUNT(*) AS occupied FROM members WHERE seat = (SELECT id FROM seats WHERE row = :ROW AND col = :COL);
Alternatively use SELECT (1 - COUNT(*)) AS vacant in the query above if it's more conveninent for you.
Find first free seat
SELECT MIN(id) FROM seats WHERE NOT EXISTS( SELECT seat FROM members WHERE seat = seats.id);
Unassign all taken seats
UPDATE members SET seat = NULL;

Merging two tables with a relationship

I am building upon an existing database with a relationship construction I've seen nowhere before.
I have three tables:
legend1
legid INT(11), AUTO_INCREMENT, PRIMARY
description VARCHAR(255)
legend2
legid INT(11), AUTO_INCREMENT, PRIMARY
description VARCHAR(255)
items
id INT(11), AUTO_INCREMENT, PRIMARY
name VARCHAR(255)
legid INT(11)
legend VARCHAR(8)
Every record in items relates to data in either legend1 or legend2.
The field items.legend determines wich one it is. I want to get rid of this construction as legend1 and legend2 have an identical structure. The only thing different is the content.
I want to have this construction:
legend
legid INT(11), AUTO_INCREMENT, PRIMARY
description VARCHAR(255)
items
id INT(11), AUTO_INCREMENT, PRIMARY
name VARCHAR(255)
legid INT(11)
The problem is that the tables are full and no data may be lost. The id of both tables starts on 1 so almost every primary key will collide.
I have this query:
INSERT INTO legend1 (description) SELECT description FROM legend2;
This query doesn't work because it messes up referenced id's from legend2.
After you have executed your insert query:
INSERT INTO legend1 (description) SELECT description FROM legend2;
Perform the following query
UPDATE items SET legid = (SELECT legid FROM legend1 WHERE legend1.description = items.description) WHERE legend ='something to define that it is from the legend2 table'
Note that I haven't tried the query out but the solution is somewhat like this. If you pick out the syntax errors I've made I'm sure it will work.
What it does is the following:
After you insert your entire legend2 table into the legend1 table you update your items table to set the corresponding legendid