Correct database? Does it need altering? - mysql

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;

Related

How to use more than 1 auto-increment column in MySQL

I want to create a table name Users where I should have have columns User, cookieID, sessionID, Geo and then I want to first three columns to have some random unique value assigned automatically. I tried to make all three columns AUTO_INCREMENT with User column PRIMARY and 'cookieIDandsessionIDcolumnUNIQUE`. The SQL code is:
CREATE TABLE `users` ( `User` VARCHAR(20) NOT NULL AUTO_INCREMENT ,
`cookieID` INT(20) NULL DEFAULT NULL AUTO_INCREMENT ,
`sessionID` INT(20) NULL DEFAULT NULL AUTO_INCREMENT ,
`Geo` VARCHAR(30) NULL DEFAULT NULL ,
PRIMARY KEY (`User`), UNIQUE (`cookieID`), UNIQUE (`sessionID`), UNIQUE (`Geo`));
But, it did not work because only one column can be declared as AUTO_INCREMENT which must be PRIMARY.
What is the another approach to do this?
Since the auto-increment cannot be applied to multiple to rows and there no option for sequence in MySQL. You can use triggers for the unique update of the row with datetime.
Change to table creation to be of single auto-increment row.
CREATE TABLE `users` ( `User` VARCHAR(20) NOT NULL,
`cookieID` INT(20) NULL DEFAULT NULL,
`sessionID` INT(20) NULL DEFAULT NULL AUTO_INCREMENT ,
`Geo` VARCHAR(30) NULL DEFAULT NULL,
PRIMARY KEY (`User`), UNIQUE (`cookieID`), UNIQUE (`sessionID`), UNIQUE (`Geo`));
Create a trigger on the same table as below. You can set the unique values under the SET for as many column as you want.
CREATE DEFINER=`root`#`localhost` TRIGGER `users_BEFORE_INSERT` BEFORE INSERT ON `users` FOR EACH ROW BEGIN
SET
NEW.cookieID = (SELECT curdate()+curtime());
END
Now when you insert into the table as below.
insert into `users`(`User`) values("test");
You table looks like this.
User cookieID sessionID Geo
test 20315169 0 NULL
If the value which are auto incrementing, you wanna keep both values the same. Then copy the value of one column to another during insertion time of new value.

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.

MySQL : increment a column by one after insert through a trigger

So here it is guys,
I have four tables.
My first one :
CREATE TABLE IF NOT EXISTS `Users` (
`Id_User` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`Firstname` varchar(20) NOT NULL,
`Lastname` varchar(20) NOT NULL,
PRIMARY KEY (`Id_User`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1002 ;
It contains the people's data.
My second one :
CREATE TABLE IF NOT EXISTS `Subject` (
`PrimaryKey_Subject` varchar(4) NOT NULL,
`Subject_Name` int(5) NOT NULL,
PRIMARY KEY (`PrimaryKey_Subject`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
It contains the subject name : mathematic, science, biology, etc...
My third one :
CREATE TABLE IF NOT EXISTS `Register` (
`ForeignKey_User` smallint(5) unsigned NOT NULL,
`ForeignKey_Lesson` varchar(4) NOT NULL,
PRIMARY KEY (`ForeignKey_User`,`ForeignKey_Lesson`),
KEY `ForeignKey_User_I` (`ForeignKey_User`),
KEY `ForeignKey_Lesson` (`ForeignKey_Lesson`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This one allows a user to register to a lesson.
My fourth one :
CREATE TABLE IF NOT EXISTS `Subject_Annex` (
`PrimaryKey_Subject` varchar(4) NOT NULL,
`Number_Registered` int(5) NOT NULL,
PRIMARY KEY (`PrimaryKey_Subject`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
And here it is,
How can I set a trigger that increment the Number_Registered each time someone register to a lesson?
For instance,
I create a user : John Doe --> Users Table.
Then afterwards, I have my Subject Table which contains all the courses: mathematics, science, biology, etc...
I can now, register, through the Register Table my freshly created user to a subject : let's say science
Then now we have the Subject_Annex Table, which through a trigger, and once my user, (John Doe), is linked to a subject, (Science), is supposed to be able to show the amount of users that registered to the subject from, (here Science),and also increase by 1 their number for each time someone register to this subject.
So to make it short,
How can I set a trigger that increments the registered number of user each time someone register to a subject ?
For example :
Primary Key Subject : Science
Number of registered : 1
(Someone else register)
Primary Key Subject : Science
Number of registered : 2
(Someone else register)
Primary Key Subject : Science
Number of registered : 2
Primary Key Subject : Mathematic
Number of registered : 1
Etc...
I managed to solved the problem by myself :
DELIMITER |
create trigger before_insert_subject_annexe
before INSERT
on Register
for each row
BEGIN
INSERT INTO Subject_Annex (PrimaryKey_Subject, Number_Registered)
VALUES (NEW.ForeignKey_Lesson, + 1)
ON DUPLICATE KEY UPDATE
Number_Registered=Number_Registered+1;
END;
DELIMITER |
Then on my Subjet_Annex Table :
CREATE TABLE IF NOT EXISTS `Subject_Annex` (
`PrimaryKey_Subject` varchar(4) NOT NULL,
`Number_Registered` int(5) NOT NULL,
PRIMARY KEY (`PrimaryKey_Subject`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
I added an unique key on Number_Registered

modeling issue with field with 4 values (1 or more)

lets say I have an account object in my application, which currently represented as:
CREATE TABLE Account (
accountId int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
PRIMARY KEY (accountId)
);
Now, Account object need to also have Solution field...and Status have 4 different possible values:
Solution1, Solution2, Solution3, Solution4
What would be the right way to represent it in the database?
Account can have few statuses, and status can have few accounts...
So at first I thought create in the db table of Solutions and than have another table to hold the relationship, but its seems too complicated for a field that have only 4 possible values...
Create a junction table to represent the relationships between accounts and solutions:
CREATE TABLE account_solution (
accountId int NOT NULL,
solutionId int NOT NULL
PRIMARY KEY (accountId, solutionId)
)
For your solution table, since there are only 4 values, you might be able to take advantage of MySQL's enum type, e.g.
CREATE TABLE solution
solutionId int NOT NULL PRIMARY KEY,
status ENUM('Solution1', 'Solution2', 'Solution3', 'Solution4')
);
You can use set Mysql SET type
CREATE TABLE Account (
accountId int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
status set('Solution1','Solution2','Solution3','Solution4') NOT NULL,
PRIMARY KEY (accountId)
);
And if you want to select a specific status
SELECT *
FROM `Account`
WHERE FIND_IN_SET( 'Solution2', `status` ) >0

create relationship between tables

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.