MySQL Null and Joins vs Tables - php

In this code:
CREATE TABLE `institution` (
`id` SMALLINT UNSIGNED AUTO_INCREMENT,
`name` VARCHAR(70) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE TABLE announcement (
`id` INT UNSIGNED AUTO_INCREMENT,
`institution` SMALLINT UNSIGNED NOT NULL,
`content` TEXT NOT NULL,
CONSTRAINT `fk_announcement_institution`
FOREIGN KEY (`institution`) REFERENCES `institution` (`id`),
PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE TABLE `reaction` (
`id` BIGINT UNSIGNED AUTO_INCREMENT,
`announcement` INT UNSIGNED NOT NULL,
`user` INT UNSIGNED,
`content` TEXT NOT NULL,
CONSTRAINT `fk_reaction_announcement`
FOREIGN KEY (`announcement`) REFERENCES `announcement` (`id`),
CONSTRAINT `fk_reaction_user`
FOREIGN KEY (`user`) REFERENCES `user` (`id`),
PRIMARY KEY (`id`))
ENGINE = InnoDB;
The reaction can be added by a user or an institution (the one who created the announcement in the first place), I've decided to use the "user" column to determine the student who added the reaction and if it's null i'll determine it's the institution.
Is that's okay? to use null this way? or should i do it like this (so i left join to determine which belongs to user and which's belong to the institution):
CREATE TABLE `institution` (
`id` SMALLINT UNSIGNED AUTO_INCREMENT,
`name` VARCHAR(70) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE TABLE announcement (
`id` INT UNSIGNED AUTO_INCREMENT,
`institution` SMALLINT UNSIGNED NOT NULL,
`content` TEXT NOT NULL,
CONSTRAINT `fk_announcement_institution`
FOREIGN KEY (`institution`) REFERENCES `institution` (`id`),
PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE TABLE `reaction` (
`id` BIGINT UNSIGNED AUTO_INCREMENT,
`announcement` INT UNSIGNED NOT NULL,
`content` TEXT NOT NULL,
CONSTRAINT `fk_reaction_announcement`
FOREIGN KEY (`announcement`) REFERENCES `announcement` (`id`),
PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE TABLE `reaction_user` (
`reaction` BIGINT UNSIGNED,
`user` INT UNSIGNED,
CONSTRAINT `fk_reaction_user_reaction`
FOREIGN KEY (`reaction`) REFERENCES `reaction` (`id`),
CONSTRAINT `fk_reaction_user_user`
FOREIGN KEY (`user`) REFERENCES `user` (`id`),
PRIMARY KEY (`reaction`, `user`))
ENGINE = InnoDB;
Another question two please:
Which's better more tables and less joins or more joins and less tables?
And...
I've read in a lot of questions here in stack-overflow is that InnoDB stores null values with only 1 bit, but here in manual says: "An SQL NULL value reserves one or two bytes in the record directory. Besides that, an SQL NULL value reserves zero bytes in the data part of the record if stored in a variable length column. In a fixed-length column, it reserves the fixed length of the column in the data part of the record. Reserving the fixed space for NULL values enables an update of the column from NULL to a non-NULL value to be done in place without causing fragmentation of the index page". So Who's right?
Thank you.

Related

Many to Many Relationship with extra field and 4th table foreign key with Mysql and Propel

I am designing a database that will keep track of users and their relationship with different organizations. A user can belong to many organizations, and an organization can have many users. That part is simple to solve with a Many to Many relationship. However, where things get a little more fuzzy is that a user can also be an admin to one or more of the organizations, and a user needs to be able to log time spend with each organization.
It seems that there are many ways to solve this. Here is the table structure I have so far, I would like your opinion if you think there is a better way.
CREATE TABLE `organization` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
PRIMARY KEY (`id`)
);
CREATE TABLE `user` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`first_name` VARCHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`last_name` VARCHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`email` VARCHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`password` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
PRIMARY KEY (`id`),
UNIQUE INDEX `email` (`email`)
);
CREATE TABLE `time_log` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_organization_id` INT(11) NOT NULL,
`date` DATE NOT NULL,
`time` TINYINT(4) NOT NULL,
PRIMARY KEY (`id`),
INDEX `user_organization_id` (`user_organization_id`),
CONSTRAINT `fk_time_log_user_organization` FOREIGN KEY (`user_organization_id`) REFERENCES `user_organization` (`id`)
);
CREATE TABLE `user_organization` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` INT(11) NOT NULL,
`organization_id` INT(11) NOT NULL,
`admin` TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`, `user_id`, `organization_id`, `admin`) USING BTREE,
INDEX `user_id` (`user_id`),
INDEX `organization_id` (`organization_id`),
CONSTRAINT `fk_user_organization_organization` FOREIGN KEY (`organization_id`) REFERENCES `organization` (`id`),
CONSTRAINT `fk_user_organization_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
);
I chose to go with an id field on the user_organization table because it made creating a foreign key to the time_log table easier. However, I could also just put the user_id, and organization_id in the time_log table as well.
CREATE TABLE `user_organization` (
`id` INT(11) NOT NULL AUTO_INCREMENT, -- remove
`user_id` INT(11) NOT NULL, -- don't you want INT UNSIGNED?
`organization_id` INT(11) NOT NULL,
`admin` TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`, `user_id`, `organization_id`, `admin`) USING BTREE, -- Bad!
INDEX `user_id` (`user_id`), -- see below
INDEX `organization_id` (`organization_id`),
CONSTRAINT `fk_user_organization_organization` FOREIGN KEY (`organization_id`) REFERENCES `organization` (`id`),
CONSTRAINT `fk_user_organization_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
);
-->
CREATE TABLE `user_organization` (
`user_id` INT(11) NOT NULL,
`organization_id` INT(11) NOT NULL,
`admin` TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`user_id`, `organization_id`) -- PK, and lookup from user
INDEX `organization_id` (`organization_id`, user_id), -- lookup the other way
CONSTRAINT `fk_user_organization_organization` FOREIGN KEY (`organization_id`) REFERENCES `organization` (`id`),
CONSTRAINT `fk_user_organization_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB; -- don't let it default to MyISAM
It's not a good idea to flag the admin in the intersection table. What happens if none of the users of a particular organization are flagged or if more than one is flagged for the same organization? One good way is to have a separate OrgAdmins table.
create table OrgAdmins(
UserID int not null,
OrgID int not null,
Assigned date not null,
constraint PK_OrgAdmins primary key( OrgID ),
constraint FK_OrgAdmins_OrgUser foreign key( UserID, OrgID )
references user_organization( user_id, organization_id )
);
Making OrgID the key field limits one entry for each organization. Making the UserID, OrgID reference the intersection table assures that the admin is properly defined as a user of the organization.
A similar layout can work for the time log table. But is that time the total time per user for an organization or is there an entry for each time period the user "spends time" at the organization? If the former, then (UserID, OrgID) pair would be the primary key as well as a foreign key. If the latter, this is an "event" table which generally does not have a primary key -- multiple entries could occur for each reference and are differentiated by the date and time of the event.

How to insert data into 3 tables?

I have 3 tables called book , author, publisher. The relationship between book and author is a resolving table called book_author_link. The main issue is that when a user adds a book, it was not successfully added as some of the fields belonged in multiple tables. Therefore I am currently having trouble with the INSERT query. How do I go about doing this?
Here is my PHP:
$queryInsert = "INSERT INTO book,author,
publishers(title,isbn,author_name,publisher_name,year_published, book_desc,genre_id,keywords)
FROM book b, author a ,book_author_link ba, publishers p
VALUES ('$title',$isbn,'$author_name','$publisher_name',$year_published,'$genre_type','‌​$book_desc','$genre_id','$keywords')
WHERE b.book_id = ba.book_id AND a.author_id = ba.author_id AND b.publisher_id = p.publisher_id";
Here is my book table:
CREATE TABLE IF NOT EXISTS `fyp`.`book` (
`book_id` INT NOT NULL AUTO_INCREMENT,
`title` VARCHAR(45) NOT NULL,
`ISBN` VARCHAR(45) NOT NULL,
`book_desc` VARCHAR(100) NOT NULL,
`year_published` VARCHAR(45) NOT NULL,
`year_of_birth` YEAR NOT NULL,
`image` VARCHAR(45) NULL,
`genre_id` INT NOT NULL,
`publisher_id` INT NOT NULL,
`user_id` INT NOT NULL,
PRIMARY KEY (`book_id`),
INDEX `fk_book_publishers1_idx` (`publisher_id` ASC),
INDEX `fk_book_user1_idx` (`user_id` ASC),
INDEX `fk_book_genre1_idx` (`genre_id` ASC),
CONSTRAINT `book_publishers_key`
FOREIGN KEY (`publisher_id`)
REFERENCES `fyp`.`publishers` (`publisher_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `book_user_key`
FOREIGN KEY (`user_id`)
REFERENCES `fyp`.`user` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `book_genre_key`
FOREIGN KEY (`genre_id`)
REFERENCES `fyp`.`genre` (`genre_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- Table fyp.author
CREATE TABLE IF NOT EXISTS `fyp`.`author` (
`author_id` INT NOT NULL AUTO_INCREMENT,
`author_name` VARCHAR(45) NOT NULL,
`year_of_birth` YEAR NOT NULL,
`year_deceased` YEAR NULL,
`image` VARCHAR(45) NULL,
`user_id` INT NOT NULL,
`country_id` INT NOT NULL,
`gender_id` INT NOT NULL,
PRIMARY KEY (`author_id`),
INDEX `fk_author_user1_idx` (`user_id` ASC),
INDEX `fk_author_country1_idx` (`country_id` ASC),
INDEX `fk_author_gender1_idx` (`gender_id` ASC),
CONSTRAINT `author_user_key`
FOREIGN KEY (`user_id`)
REFERENCES `fyp`.`user` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `author_country_key`
FOREIGN KEY (`country_id`)
REFERENCES `fyp`.`country` (`country_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `author_gender_key`
FOREIGN KEY (`gender_id`)
REFERENCES `fyp`.`gender` (`gender_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- Table fyp.publishers
DROP TABLE IF EXISTS `fyp`.`publishers` ;
CREATE TABLE IF NOT EXISTS `fyp`.`publishers` (
`publisher_id` INT NOT NULL,
`publisher_name` VARCHAR(45) NOT NULL,
PRIMARY KEY (`publisher_id`))
ENGINE = InnoDB;
-- Table fyp.book_author_link
DROP TABLE IF EXISTS fyp.book_author_link ;
CREATE TABLE IF NOT EXISTS `fyp`.`book_author_link` (
`book_author_link_id` INT NOT NULL AUTO_INCREMENT,
`book_id` INT NOT NULL,
`author_id` INT NOT NULL,
PRIMARY KEY (`book_author_link_id`),
INDEX `fk_book_author_link_book_idx` (`book_id` ASC),
INDEX `fk_book_author_link_author1_idx` (`author_id` ASC),
CONSTRAINT `book_key`
FOREIGN KEY (`book_id`)
REFERENCES `fyp`.`book` (`book_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `author_key`
FOREIGN KEY (`author_id`)
REFERENCES `fyp`.`author` (`author_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
I recommend running the queries in a transaction: http://php.net/manual/pdo.transactions.php
Also, you might need this to get the AUTO_INCREMENT id: http://php.net/manual/de/pdo.lastinsertid.php
Are you using phpMyAdmin as GUI? Have you tried running your SQL there? If there is a "relationship issue", it should print the exact error message. You should provide it here.
you could give a try to a trigger AFTER INSERT on the main table.

ID auto increase but not unique

I have a table that I want to have an id that will auto increase itself but not be primary or unique.
Is this possible?
You should really create another table, in that case.
E.g.
CREATE TABLE `Calls` (
`Id` INT(10) AUTO_INCREMENT,
`From` VARCHAR(100) NOT NULL,
`To` VARCHAR(100) NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=INNODB;
CREATE TABLE `CallHistory` (
`Id` INT(15) AUTO_INCREMENT,
`CallId` INT(10) NOT NULL,
`Text` VARCHAR(255) NOT NULL,
PRIMARY KEY (`Id`),
KEY `CallHistory_Calls_idx` (`CallId`),
CONSTRAINT `CallHistory_Calls`
FOREIGN KEY (`CallId`)
REFERENCES `calls` (`Id`)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=INNODB;
Here's a demo on SQLFiddle.
A benefit of this is that if you delete a row from Calls, the rows in CallHistory will also be deleted.
Running this query:
SELECT `Calls`.`Id`,
`Calls`.`From`,
`Calls`.`To`,
`CallHistory`.`Text`
FROM `Calls`, `CallHistory`
WHERE `Calls`.`Id` = `CallHistory`.`CallId`;
Gives results something like this:
This should work:
id int NOT NULL AUTO_INCREMENT
Anyway I don't see how it wouldn't stay unique unless you update existing values later
Yes, you need to set auto_increment constraint:
CREATE TABLE `test` (
`testID` int(11) NOT NULL, //primary key here
`testInc` int(11) NOT NULL AUTO_INCREMENT, //here is your non-primary auto increment column
PRIMARY KEY (`testID`),
KEY `testInc` (`testInc`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
and if you want this to be unique also then you may add unique constraint:
ALTER TABLE `test` ADD CONSTRAINT ux_unique_constraint UNIQUE `testInc`

#1005 - Can't create table 'database.viewers' (errno: -1)

this table is already work fine
create table posts (
id bigint(20) unsigned not null auto_increment,
title varchar(200) not null,
content text,
mdesc varchar(340),
pdate timestamp not null default current_timestamp,
lupdate timestamp not null default '0000-00-00 00:00:00',
perma varchar(120) not null,
cat_id smallint(5) unsigned not null,
user_id int(11) unsigned not null,
views int(11) unsigned not null default 0,
status tinyint(1) unsigned not null default 0,
primary key (id),
unique key (title,cat_id),
foreign key (cat_id) references category (id) on delete restrict on update cascade,
foreign key (user_id) references users (id) on delete cascade on update cascade
) engine=innodb default charset=utf8;
but i dont know why i cant query viewers table i dont know why
create table viewers (
id int(11) unsigned not null auto_increment,
post_id bigint(20) unsigned not null,
primary key (id),
foreign key (post_id) references posts (id) on delete cascade
) engine=innodb default charset=utf8;
please help :)
Please try removing fks
Most commonly it is because of different properties.
Check
if id of post table is having same properties as of this? (here bigint)
Other possibilities could be
it isn't innodb engine for other table.
Names of fks are not unique

Troubled with making a PHP db driven multiple choice Quiz

So my objective sounds simple, I need to make a db driven multiple choice quiz
CMS to add into my project. I need to be able to create quizzes by category, add 10 questions per quiz, and 4 questions with 1 answer. I've been troubled in 2 areas.
Database structure. How can I structure my database so that I can do this? eg, a table for each questions, question_answers, and quizzes?
After the users takes the quiz, I want to grab the score and store it into its own table. I know how to put the score into the database, but how would I display the quiz, with the corresponding question, with the corresponding answers, and the correct answer with the right radio button?
It's very tricky to me, but maybe not to some of you geniuses out there.
Best regards,
Sean
Clicked this table structure for you. The foreign key constraints are optional.
CREATE TABLE IF NOT EXISTS `answer` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`question_id` int(10) unsigned NOT NULL,
`answer` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
KEY `question_id` (`question_id`)
) ENGINE=InnoDB ;
CREATE TABLE IF NOT EXISTS `question` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`quiz_id` int(10) unsigned NOT NULL,
`question` varchar(500) NOT NULL,
`correct_anwer_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `quiz_id` (`quiz_id`,`correct_anwer_id`),
KEY `correct_anwer_id` (`correct_anwer_id`)
) ENGINE=InnoDB ;
CREATE TABLE IF NOT EXISTS `quiz` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`category` int(10) unsigned NOT NULL,
`title` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB ;
ALTER TABLE `answer`
ADD CONSTRAINT `answer_ibfk_1` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`);
ALTER TABLE `question`
ADD CONSTRAINT `question_ibfk_2` FOREIGN KEY (`correct_anwer_id`) REFERENCES `answer` (`id`),
ADD CONSTRAINT `question_ibfk_1` FOREIGN KEY (`quiz_id`) REFERENCES `quiz` (`id`);
And for storing the test, users have taken:
CREATE TABLE IF NOT EXISTS `test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`quiz_id` int(10) unsigned NOT NULL,
`date_taken` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`score` mediumint(9) NOT NULL,
PRIMARY KEY (`id`),
KEY `quiz_id` (`quiz_id`)
) ENGINE=InnoDB ;
CREATE TABLE IF NOT EXISTS `test_answer` (
`test_id` int(10) unsigned NOT NULL,
`question_id` int(10) unsigned NOT NULL,
`answer_id` int(10) unsigned NOT NULL,
`single_score` mediumint(9) NOT NULL,
PRIMARY KEY (`test_id`,`question_id`),
KEY `question_id` (`question_id`),
KEY `answer_id` (`answer_id`)
) ENGINE=InnoDB ;
ALTER TABLE `test`
ADD CONSTRAINT `test_ibfk_1` FOREIGN KEY (`quiz_id`) REFERENCES `quiz` (`id`);
ALTER TABLE `test_answer`
ADD CONSTRAINT `test_answer_ibfk_3` FOREIGN KEY (`answer_id`) REFERENCES `answer` (`id`),
ADD CONSTRAINT `test_answer_ibfk_1` FOREIGN KEY (`test_id`) REFERENCES `test` (`id`),
ADD CONSTRAINT `test_answer_ibfk_2` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`);
Some sample data to play around:
INSERT INTO `answer` (`id`, `question_id`, `answer`) VALUES
(3, 1, 'stackoverflow.com '),
(4, 1, 'example.com');
INSERT INTO `question` (`id`, `quiz_id`, `question`, `correct_anwer_id`) VALUES
(6, 1, 'What is the best website on the whole internet?', 3);
INSERT INTO `quiz` (`id`, `category`, `title`) VALUES
(1, 1337, 'My Great Quiz. Take me!');

Categories