create table Board (
boardID char(30) not null,
readLevel tinyint not null,
writeLevel tinyint not null,
PRIMARY KEY (boardID) ) engine=InnoDB character set=utf8;
create table Post (
postID int not null AUTO_INCREMENT,
title char(50) not null,
content TEXT not null,
writeDate date not null,
readCount int not null,
PRIMARY KEY (postID)) engine=InnoDB character set=utf8;
create table Save_Board_Post(
boardID char(30) not null,
postID int not null,
FOREIGN KEY (boardID) REFERENCES Board(boardID) ON UPDATE CASCADE,
FOREIGN KEY (postID) REFERENCES Post(postID) ON UPDATE CASCADE ) engine=InnoDB character set=utf8;
insert into Board (boardID, readLevel, writeLevel) values ('testBoard', 0, 0);
insert into Post (title, content, writeDate, readCount) values ('testPost1', 'test', CURRENT_TIMESTAMP() ,0);
select * from Board where boardID='testBoard';
select * from Post where tile='testPost1';
select * from Save_Board_Post where boardID='testBoard';
I'm rookie in sql. and I'm not native about English.
So, Please forgive my English skills.
Here's my mysql code.
Last five lines are for test. And select from Board and Post is working fine.
But
select * from Save_Board_Post where boardID= 'testBoard';
It doesn't work. This code has no error. but there is no output result.
I guess it means no data in Save_Board_Post table.
I thought REFERENCES command is automatically creation data when insert parent table.
If it does not, please let me know how to automatically creation in relation data.
No, that's not what REFERENCES does. All that your REFERENCES constraints mean is that every row that is inserted (manually) into the Save_Board_Post table must have a boardID and a postID that exist in the Board and Post tables. Nothing is inserted into that table automatically.
If you are trying to represent what board a post is in, the appropriate way to do this would be to make the board ID be a property of the post, e.g.
CREATE TABLE Post (
postID INTEGER NOT NULL AUTO_INCREMENT,
boardID CHAR(30) NOT NULL,
...
FOREIGN KEY (boardID) REFERENCES Board(boardID)
);
rather than having an entirely separate table just for that data.
You cannot automatically insert data in child table by inserting in the parent table. You got it right when you said it failed because there was no data in the table. Referential integrity exist to remove redundancy in a database. I dont think there is a way for you to automatically insert into the child table by inserting into a parent table. you have to do it manually.
Related
I have a database containing over 1,000 item information and I am now developing a system that will have this check the API source via a regular Cron Job adding new entries as they come. Usually, but not always the case, when a new item is released, it will have limited information, eg; Image and name only, more information like description can sometimes be initially withheld.
With this system, I am creating a bulletin to let everyone know new items have been released, so like most announcements, they get submitted to a database, however instead of submitting static content to the database for the bulletin, is it possible to submit something which will be executed upon the person loading that page and that bulletin data is firstly obtained then the secondary code within run?
, For example, within the database could read something like the following
<p>Today new items were released!</p>
<?php $item_ids = "545, 546, 547, 548"; ?>
And then on the page, it will fetch the latest known information from the other database table for items "545, 546, 547, 548"
Therefore, there would be no need to go back and edit any past entries, this page would stay somewhat up-to-date dynamically.
Typically you would do something like have a date field on your items, so you can show which items were released on a given date. Or if you need to have the items associated with some sort of announcement record, create a lookup table that joins your items and announcements. Do not insert executable code in the DB and then pull it out and execute it.
CREATE TABLE `announcements` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`publish_date` DATETIME NOT NULL,
`content` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `items` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`title` VARCHAR(128) NOT NULL,
`description` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `announcement_item_lkp` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`announcement_id` int(11) unsigned NOT NULL,
`item_id` int(11) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `announcement_item_lkp_uk1` (`announcement_id`,`item_id`),
KEY `announcement_item_lkp_fk_1` (`announcement_id`),
KEY `announcement_item_lkp_fk_2` (`item_id`),
CONSTRAINT `announcement_item_lkp_fk_1` FOREIGN KEY (`announcement_id`) REFERENCES `announcements` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `announcement_item_lkp_fk_2` FOREIGN KEY (`item_id`) REFERENCES `items` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
With the announcement_item_lkp table, you can associate as many items to your announcement as you like. And since you have cascading deletes, if an item gets deletes, its lookup records are deleted as well, so you don't have to worry about orphaned references in your announcements, like you would it you just stuff a string of IDs somewhere.
You're already using a relational database, let it do its job.
I am new to SQL and looking for some help. I have three tables: author, study and casestudy (which is a linking table). What I want to achieve is when data is inserted into author and study tables (from a web form) their Auto increment IDs get inserted into casestudy table if it is possible. I guess I will need to create triggers. AuthorId and StudyId in casestudy table is a composite key. Table structure is as follow:
CREATE TABLE `test`.`author` (
`AuthorId` INT(11) NOT NULL AUTO_INCREMENT,
`AuthorTitle` VARCHAR(45) NOT NULL,
PRIMARY KEY (`AuthorId`),
UNIQUE INDEX `AuthorId_UNIQUE` (`AuthorId` ASC));
CREATE TABLE `test`.`study` (
`StudyId` INT(11) NOT NULL AUTO_INCREMENT,
`Title` VARCHAR(45) NOT NULL,
PRIMARY KEY (`StudyId`),
UNIQUE INDEX `StudyId_UNIQUE` (`StudyId` ASC));
CREATE TABLE `test`.`casestudy` (
`AuthorId` INT(11) NOT NULL,
`StudyId` INT(11) NOT NULL,
PRIMARY KEY (`AuthorId`, `StudyId`),
INDEX `StudyId_idx` (`StudyId` ASC),
CONSTRAINT `AuthorId`
FOREIGN KEY (`AuthorId`)
REFERENCES `test`.`author` (`AuthorId`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `StudyId`
FOREIGN KEY (`StudyId`)
REFERENCES `test`.`study` (`StudyId`)
ON DELETE NO ACTION
ON UPDATE NO ACTION);
Any advice will be appreciated. Thank you.
As far as I can see there is no data link between author and study tables. There is no such functionality as "one trigger on two tables update at a time". The best place to implement casestudy maintenance is in the procedure that populates the author and study tables during web form processing.
In PHP that can be done through collecting IDs after each Insert using mysql_insert_id(); (see Inserting data into multiple tables using php via a web form) and then using them all to update the linking table.
Using mysqli (and assuming $mysqli is the connection) that should be something like:
$AuthorTitle = $mysqli->real_escape_string($_POST[AuthorTitle value]);
$mysqli->query("INSERT INTO test.author(AuthorTitle) VALUES('$AuthorTitle')");
$AuthorId = $mysqli->insert_id;
$StudyTitle = $mysqli->real_escape_string($_POST[StudyTitle value]);
$mysqli->query("INSERT INTO test.study(Title) VALUES('$StudyTitle')");
$StudyId = $mysqli->insert_id;
$mysqli->query("INSERT INTO test.casestudy(AuthorId, StudyId) VALUES($AuthorId, $StudyId)");
Alternatively all three tables can be consistently populated through a stored procedure (or just an SQL script) that would take care of all the relevant web form fields in one go. Then after each Insert auto-generated ID can be collected using LAST_INSERT_ID(); (see LAST_INSERT_ID() MySQL).
$AuthorTitle = $mysqli->real_escape_string($_POST[AuthorTitle value]);
$StudyTitle = $mysqli->real_escape_string($_POST[StudyTitle value]);
$mysqli->multi_query("
START TRANSACTION;
INSERT INTO test.author(AuthorTitle) VALUES('$AuthorTitle');
SET #AuthorId = LAST_INSERT_ID();
INSERT INTO test.study(Title) VALUES('$StudyTitle');
SET #StudyId = LAST_INSERT_ID();
INSERT INTO test.casestudy(AuthorId, StudyId) VALUES(#AuthorId, #StudyId);
COMMIT;
");
Finally this scenario can be implemented through an Updatable and Insertable View across all three tables that would take care of storing the data in consistent manner.
I've got a user table, and a picture table.
The picture table has an uploader id column which is a foreign key.
It refers to the user id column in the user table.
For some reason, when I try to insert a new record into the picture table, it's not working. No error messages pop up. It just doesn't insert the new record.
INSERT INTO picture (pic_url, pic_uploader) VALUES($picurl, $uploader);
$picurl is an image src path from a file upload. The uploaded files are in the right directory, and the exact same code works perfectly for an earlier record without a foreign key.
$uploader contains the foreign key value -- from a session variable that contains the user id of the user account -- but it's not inserting it into the table.
Here's the SQL for the tables, in case that helps...
Picture table
CREATE TABLE IF NOT EXISTS picture (
pic_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
pic_url varchar(200) NOT NULL,
pic_uploader bigint(20) unsigned NOT NULL,
PRIMARY KEY (pic_id),
KEY pic_uploader (pic_uploader)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Picture constraints
ALTER TABLE picture
ADD CONSTRAINT pictures_ibfk_1 FOREIGN KEY (pic_uploader) REFERENCES user (user_id);
User table
CREATE TABLE IF NOT EXISTS user (
user_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
user_name varchar(80) NOT NULL,
user_img varchar(200) NOT NULL DEFAULT 'img/defaultpic.png',
user_email varchar(100) NOT NULL,
user_pword char(60) NOT NULL,
user_stat enum('0','1','A') NOT NULL,
PRIMARY KEY (user_id),
UNIQUE KEY user_email (user_email)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
There can be a reason that $uploader value does not exists in your user table as user_id.
First try to insert in simple way directly in db by any tool like sqlyog putty, mysqladmin etc.
INSERT INTO picture (pic_url, pic_uploader) VALUES('pic1', 'user1');
Make sure user1 should exist in user table. If it works fine then problem in your application other wise mysql will return an error by this we will be able to check the exact problem either it is due to foreign key or else. So do it and share results.
IN your picture table you are using columns NOT NULL.
But you try to insert only two values in the insert command that's why data is not inserted.
Either insert data for all columns or make columns as NULLABLE.
Thanks
I would like to have a way of controlling/tracking revisions of rows. I am trying to find the best solution for this problem.
The first thing that comes to mind is to have a table with a id to identify the row and and id for the revision number. The combined ids would be the primary key. so example data might look like this:
1, 0, "original post"
1, 1, "modified post"
1, 2, "modified again post"
How can I create a table with this behavior? or is there a better solution to do this?
I like InnoDB since it supports transactions, foreign keys and full text in MySQL 5.6+.
I know its possible to "force" this behavior by how I insert the data but I'm wondering if there is a way to have the table do this automatically.
Consider table structure:
TABLE posts
post_id INT AUTO_INCREMENT PK
cur_rev_id INT FK(revisions.rev_id)
TABLE revisions
rev_id INT AUTO_INCREMENT PK
orig_post INT FK(posts.post_id)
post_text VARCHAR
Where the posts table tracks non-versioned information about the post and its current revision, and revisions tracks each version of the post text with a link back to the parent post. Because of the circular FK constraints you'd need to enclose new post insertions in a transaction.
With this you should be able to easily add, remove, track, roll back, and preview revisions to your posts.
Edit:
Yeah, enclosing in a transaction won't exactly help since the keys are set to AUTO_INCREMENT, so you need to dip back in to PHP with LAST_INSERT_ID() and some temporarily NULL indexes.
CREATE TABLE `posts` (
`post_id` INT(10) NOT NULL AUTO_INCREMENT,
`cur_rev_id` INT(10) NULL DEFAULT NULL,
`post_title` VARCHAR(50) NULL DEFAULT NULL,
PRIMARY KEY (`post_id`),
INDEX `FK_posts_revisions` (`cur_rev_id`),
) ENGINE=InnoDB
CREATE TABLE `revisions` (
`rev_id` INT(10) NOT NULL AUTO_INCREMENT,
`orig_post` INT(10) NULL DEFAULT NULL,
`post_text` VARCHAR(32000) NULL DEFAULT NULL,
PRIMARY KEY (`rev_id`),
INDEX `FK_revisions_posts` (`orig_post`),
) ENGINE=InnoDB
ALTER TABLE `posts`
ADD CONSTRAINT `FK_posts_revisions` FOREIGN KEY (`cur_rev_id`) REFERENCES `revisions` (`rev_id`);
ALTER TABLE `revisions`
ADD CONSTRAINT `FK_revisions_posts` FOREIGN KEY (`orig_post`) REFERENCES `posts` (`post_id`);
Then:
$db_engine->query("INSERT INTO posts (cur_rev_id, post_title) VALUES (NULL, 'My post Title!')");
$post_id = $db_engine->last_insert_id();
$db_engine->query("INSERT INTO revisions (orig_post, post_text) VALUES($post_id, 'yadda yadda')");
$rev_id = $db_engine->last_insert_id();
$db_engine->query("UPDATE posts SET cur_rev_id = $rev_id WHERE post_id = $post_id");
If I've understood you correctly and the table doesn't receive large numbers of updates/deletes then you could look at setting a trigger such as:
DELIMITER $$
CREATE TRIGGER t_table_update BEFORE UPDATE ON table_name
FOR EACH ROW
INSERT INTO table_name_revisions (item_id, data, timestamp)
VALUES(OLD.id, OLD.data, NOW());
END$$
DELIMITER ;
See trigger syntax for more information
I am designing a new system for users/clients and I have in my system user preferences. Before I start to create code and the database I want to make sure I do the right thing.
I have these preferences:
font size
font face
font color
theme
home page
dashboard options
few true/false options like enable sharing etc...
and more.
My idea was to create each field for each preferences but I thouhgt maybe I can save an object or array instead in a blob.
Is it a good idea?
You could make an auxiliary table to keep references of properties names. Then you can link that table with a merge table — between a user id and the id of one of the properties. Doing so, you can always change the properties.
Using Foreign keys you can also “cascade delete” user details that have a property that does not exist anymore. Furthermore, you can ensure that you add only references to valid property names, and you optimize the search by using indexes.
Let's say that:
CREATE TABLE user_preferences_headers
(
`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL
);
CREATE TABLE `users`
(
`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`pass` VARCHAR(255) NOT NULL
);
CREATE TABLE `user_preferences`
(
`id_user` INT NOT NULL,
`id_preference_entity` INT NOT NULL,
`value` VARCHAR(255)
);
ALTER TABLE `user_preferences` ADD INDEX ( `id_user` );
ALTER TABLE `user_preferences` ADD INDEX ( `id_preference_entity` );
ALTER TABLE `user_preferences` ADD FOREIGN KEY ( `id_user` ) REFERENCES `users` (
`id`
) ON DELETE CASCADE ON UPDATE CASCADE ;
ALTER TABLE `user_preferences` ADD FOREIGN KEY ( `id_preference_entity` ) REFERENCES `user_preferences_headers` (
`id`
) ON DELETE CASCADE ON UPDATE CASCADE ;
Now you first select all headers from user_preferences_headers by name, or not, and you use the id to select the desired preference value of a user (identified also by id) from user_preferences. Notice that when you delete an entry in user_preferences_headers, all entries that link to the id of the deleted row will also be deleted.
Saving them individually will make searching etc possible on each field. If you serialize them, then searching will become difficult/impossible.
You may not need that now, but it may be required further down the line.