How to relate the data in two MySQL tables? - mysql

I am designing a web app which basically has to store two kinds of elements: posts and containers (which are arrays of posts)
I have done the database so that i store in each row of the container the stringified version of the array of the posts which it holds.
The issue is that when a post is deleted each time i call the container i have the id of the post and i have to check if the post is alive or not.
Is there a better way to do this ? for example structuring the container table to hold "pointers" to the actual posts ?
Thanks a lot!

If I understand correctly, you have a one-to-many relation: each container can have many posts, but each post is related to a single container. So your database design should reflect this.
Example:
create table tbl_containers (
containerId int unsigned not null auto_increment primary key,
containerDescription varchar(100)
);
create table tbl_posts (
postId int unsigned not null auto_increment primary key,
containerId int unsigned not null,
postText varchar(100),
index idxContInd(containerId)
);
When you fill your data, every post must be associated with a container; in other words, before a post can be entered there must be a container to hold it, and if there's no "suitable" container, it should be created before the creation of the post.
After your data is in the tables, it is easy to look for the posts, and delete them, independently of the container each post belongs to.
Hope this helps you

Using a foreign key relationship between the two tables would be ideal.
First, if I understand the relationship between your data properly, your Container table would be the table that holds information relating to a unique id. The `Posts table then has its own unique id, a containerId, and the post content itself.
Drawn out, it'd look a little like this.
Container
---
id
Posts
---
id | containerId | post
The relationship between Container and Posts is presumed to be one-to-many; that is to say, one container may have many posts, but one post can't belong to many containers. If you wanted this relationship, you'd likely have to add another column for that to Posts.

Here goes the answer to back my comment that recieved some positive feedback :) although you already have answers up there.
Your Container is going to hold the posts. So it's like one basket holds many items in it.
So for each post, there's a container id. For container table - container id is primary key. posts table - post id is primary key. To have the Foreign key relationship, you set your container id as foreign key in your posts table. If this is confusing - just see the table schema below. If you want to delete any posts related to a container when the container is deleted, you can use ON CASCADE DELETE on the parent key (foreign key) to remove any orphans (childrens without parents).
If you wish to have auto incremented ID, you can use the AUTO_INCREMENT otherwise just remove it.
And please take a look sql syntax for further understanding as well.
CREATE TABLE tblParent (
`CID` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
`field2` varchar(100),
`field3` varchar(100)
);
CREATE TABLE tblchild (
`PID` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
`PCID` int NOT NULL,
`field2` varchar(100),
`field3` varchar(100),
FOREIGN KEY REFERENCE tblParent ('CID')
ON DELETE CASCADE
);

I'm not sure if I understood you correctly but I would do this the other way around: You have your POST table, which has a field called container_ID. If the post gets deleted then a row in the POST table would get removed (including the pointer to its parent entity in the container_ID). In this case you can create a foreign key relations between the tables in order to keep the data consistent and relations intact within the database. Please clarify if I misunderstood something..

You can create a third table with two fields, 'container_id' and 'post_id' for example.
Then when you delete a post, you delete all entries containing the post_id, same thing for containers. Make sure that the table primary_key is composed by the two_fields to avoid entries duplication.

Related

Is it possible to remove an ID where it is not used?

I have a table with the following structure
CREATE TABLE Products (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(30) NOT NULL,
code VARCHAR(30) NOT NULL UNIQUE,
warranty TINYINT(1) NOT NULL,
producing_country VARCHAR(50),
)
Each product in my table has a unique code and This products is also known in stock as this codes
Codes are something like this: (AR-X22 , RF-3654, ...)
My question is can i remove the ID cloumn in this table? Because it has no special application
And does it hurt if I want to use the code column instead of id in join ?
Its good practice to have a table with an id INT AUTO_INCREMENT and PRIMARY KEY.
It makes sure each row is unique. If other programmers come and look at your table they will expect to see an id column.
Having a VARCHAR as a unique row key is is asking for trouble. There are all sorts of encoding troubles and things that can make strings as identifiers unreliable.
For example: "ABX-112" and "ABX -112" (space hidden in there)
If you just don't want to see ID column do like ravioli states below and just make a new view and not show it.
Good luck.
Your id column is specified as your PK, which means it's used to uniquely identify that row in your table. It looks like it's an identity-type field, which should take care of the uniqueness requirement.
If you want to use code as your new "id" field, that should be fine as long as you make sure it's a unique value when you add rows. It shouldn't have any effect on joins as long as you update your other tables to use the new code field.
I don't know how easy it is to fiddle with PK's on a table that already has data. Your best bet is to create a new table without the id field and populate it using the data in your current table.
If it's just a matter of not wanting to see / deal with an id field you never use, you can always create a view and exclude that field from being returned.
As per my understanding, You want to remove Id from the table and want to use Product code at that place.
A table relationship is based on the primary and foreign key constraints and it is not necessary that every time you have to Id column as primary key.
If you have product code and which will always be unique and not null
then you can use Code as the primary key for the table rather then
unnecessary Id column.
It will also work if you do not create a column wither primary.
Thanks.

Data Model, alternative to EAV

I have a Product Database, and I want to attach text, images, videos to the products. I also want that each entity (text, images or videos) have a tag, for further organisation on application.
I thought of using this model:
Content:
content_id|content_product_id|content_type|content_tag_id|content_url|content_title|content_text
Tag
tag_id|tag_name
This mean to use Entity(content_product_id) - Attribute(content_tag_id) - Value (content_url or content_title|content_text) Model.
After reading a lot, I understood that is a bad idea to use this modeling pattern (described as a database antipattern, unscalable and causing performance issues), have you an idea for an alternative method for this ?
I want to use Doctrine ORM, and I would like to find an method that will be easily compatible with that data mapper
I'd create a general table for any type of content:
CREATE TABLE ProductContents(
content_id INT AUTO_INCREMENT PRIMARY KEY,
content_type INT NOT NULL
-- other general attributes like when it was created, by whom, etc.
);
For each text, image, or video, insert one row into this table. If you use an auto-increment primary key, this table is responsible for generating the id number.
For tags, now you simply have a many-to-many relationship between ProductContent and Tags. This is represented by an intersection table.
CREATE TABLE Tags (
tag_id INT AUTO_INCREMENT PRIMARY KEY,
tag TEXT NOT NULL
);
CREATE TABLE ProductContentTagged (
content_id INT,
tag_id INT,
PRIMARY KEY (content_id, tag_id),
FOREIGN KEY (content_id) REFERENCES ProductContents(content_id),
FOREIGN KEY (tag_id) REFERENCES Tags(tag_id),
);
Then if you have any attributes specific to each type of content, create auxiliary tables for each type, with a one-to-one relationship to the content table.
CREATE TABLE ProductContentTexts (
content_id INT PRIMARY KEY,
content TEXT NOT NULL,
FOREIGN KEY (content_id) REFERENCES ProductContents(content_id)
);
CREATE TABLE ProductContentImages (
content_id INT PRIMARY KEY,
image_path TEXT NOT NULL,
FOREIGN KEY (content_id) REFERENCES ProductContents(content_id)
);
CREATE TABLE ProductContentVideos (
content_id INT PRIMARY KEY,
video_path TEXT NOT NULL,
FOREIGN KEY (content_id) REFERENCES ProductContents(content_id)
);
Note these auxiliary tables don't have an auto-increment column. They don't need to -- they will always use the value that was generated by the ProductContents table, and you're responsible for inserting that value.
Bill Karwin's answer is very good.
However, since you say:
I want to use Doctrine ORM, and I would like to find an method that will be easily compatible with that data mapper
I'll relate his answer to that particular ORM.
What Bill describes is inheritance. You have a superclass of "content", represented by a table that holds all the shared data. Then you have subclasses (text, image, video) that extend that superclass by adding content-type-specific columns.
Doctrine2 will do essentially what Bill has suggested when you use class-table inheritance. Once you configure your entities properly, it will create a set of tables very similar to what Bill describes.
So, with Doctrine you cave the Content entity, which is extended by Image, Text, and Video.
As far as the tagging goes, you would just create a basic Tag entity, and Content would have a ManyToMany relationship to Tag. Doctrine will handle creating the intermediate table for you.

MySQL table design - refer to multiple foreign rows

Minimilized background (ie in bare pseudo code details)
I am making a record keeping (among other things) php/mysql app for my farm. There are lots of types of animals etc that could have pictures (or other records - videos etc.) but just for simplicity I'll only refer to one of each (Goats and Pictures). so say the
tables are approximately like so:
CREATE TABLE BMD_farmrecords_goats (
goat_id INT NOT NULL AUTO_INCREMENT,
goat_name TEXT,
...more columns but whatever, unimportant...
primary_key(goat_id))
CREATE TABLE BMD_farmrecords_pictures (
media_id INT NOT NULL AUTO_INCREMENT,
media_name TEXT,
media_description TEXT,
media_description_short TEXT,
media_date_upload DATE,
media_date_taken DATE,
media_uploader INT, //foreign key constrained to user table but unimportant for question
media_type ENUM('jpg','gif','png'),
media_hidden BOOL,
media_category INT, //foreign key constrained to category table but unimportant for question
PRIMARY KEY (media_id)
So the problem(s):
Obviously a picture could have multiple goats in it so I can't just
have one foreign key in picture to refer to goat.
there are more than one livestock tables that would also make that a poor choice but not worried about that right now
Basically no optimization has been applied as of yet (ie no lengths set, using TEXT rather than varchar(length)) etc; I'm not worried about that until I populate it a bunch and see exactly how long I want everything.
so the question:
what is the best_ way to link a picture to multiple goats (in terms of A) best performance B) best code conformance to standards. I'm thinking I'll have to do an extra table:
create TABLE BMD_farmrecords_goatpictures (
id INT NOT NULL AUTO_INCREMENT
picture_id INT //foreign key to BMD_farmrecords_pictures->media_id
goat_id INT//foreign key to BMD_farmrecords_goats->goat_id
So is there any better way to do that?
Of course with that method I'll probably have to change *_goats table to be a parent *_animals table with then a type field and reference animal_id instead but I'm not worried about that, just about whether or not the extra table referencing both tables is the best method.
thanks;
From the discussion just changing my original idea to use a composite primary key:
create TABLE BMD_farmrecords_goatpictures (
picture_id INT //foreign key to BMD_farmrecords_pictures->media_id
goat_id INT//foreign key to BMD_farmrecords_goats->goat_id
PRIMARY KEY (picture_id, goat_id))

Unique constraint across multiple fields in MySQL

Let's say I have a table with the following fields:
primaryEmail | secondaryEmail
I know how to create a UNIQUE constraint on one of the fields, and I know how to create a UNIQUE constraint that combines both fields, but is there a way to ensure that no value exists twice, ACROSS both columns? For example, if there's a value of joe#example.com in the primaryEmail field, I don't want it to be able to appear again in either the primaryEmail field OR the secondaryEmail field.
You might consider revising your data model and pulling the email address to another table and then relating the new and old tables together. Off the top of my head, something like this should work
create table master (
id int not null primary key,
name varchar(64)
);
create table email (
id int not null primary key,
address varchar(128) not null unique,
parent_id int not null,
type enum('prim', 'secd'),
foreign key (parent_id) references master(id)
on delete cascade,
unique (parent_id, type)
);
I don't love this design - I'm not a fan of the enum, for example - but it would solve your uniqueness constraint.
In my opinion, you would want to put two separate constraints on that field if that is really what you are trying to accomplish. What you are actually trying to do are two different things (make sure that column is unique within the record, and make sure that column within that row is also unique for the whole table).

How would I create this MySQL Schema?

Suppose I have a blog post entity.
It has many attributes
It has comments attached to it.
It has many states (deleted/locked/invisible, etc).
It has many "tags". (keywords, school_id, user_id)
Obviously, comments should be its own table, with a many-to-one relationship to Blog table.
But what about "states" or "tags"? Would you put that in another table? Or would you stick that in many columns?
What about attributes...if they get too big? Because as my website grows, the blog post will have more and more attributes attached (title, author, blah, blah....). What happens if the attribute list goes as high as 100?
Here's a sample:
Again.. It's just a sample.. There are other approaches that you can use.
Here we go:
-- basic-basic blog
CREATE TABLE blog_entry (
blog_entry_id INT NOT NULL AUTO_INCREMENT,
blog_entry_title VARCHAR(255) NOT NULL,
blog_entry_text VARCHAR(4000) NOT NULL,
create_date DATETIME,
state_id INT
);
-- create a look-up table for your blog entry's state
CREATE TABLE be_state (
state_id INT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (state_id)
);
-- create a look-up table for your blog entry's tag/s
CREATE TABLE be_tag (
tag_id INT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (tag_id)
);
-- a table to store multiple tags to one entry
CREATE TABLE blog_entry_tags (
blog_entry_id INT NOT NULL,
tag_id INT NOT NULL,
PRIMARY KEY (blog_entry_id, tag_id)
);
-- a table to store definitions of attributes
CREATE TABLE be_attribute (
attribute_id INT NOT NULL AUTO_INCREMENT,
name CHAR(30)
);
-- now have a table to which you can assign multiple attributes to one blog
-- of course, this is if I understand you correctly
-- where you want to have additional attributes
-- aside from the basic properties of a blog entry
-- and will allow you, if you choose to do it
-- to not necessarily have all attributes for each entry
CREATE TABLE blog_entry_attributes (
blog_entry_id INT NOT NULL,
attribute_id INT NOT NULL,
PRIMARY KEY (blog_entry_id, attribute_id)
-- PK enforces one blog entry may have only one attribute of its type
-- meaning, no multiple attributes of 'location' attribute,
-- for example, for one blog. Unless of course you wrote half the entry
-- in one location and finished it in the next.. then you should
-- NOT enforce this primary key
);
blog_entry - your main table, where the goods go
be_state - define them here, and insert their state_id values in blog_entry.state_id
be_tag - have multiple tags like we do here
blog_entry_tags - since you can possibly have many tags for one blog entry, store them here and insert blog_entry.blog_entry_id and the corresponding be_tag.tag_id together. one tag of its type per blog entry. meaning you can't tag entry#1 (for example) the tag php twice or more.
be_attribute - store attribute definitions here like location, author, etc
blog_entry_attributes - similar to blog_entry_tags where you can assign one or more than one be_attribute to a blog entry.
Again, this is just one approach.
first of all, states should be a tightly structured thing, so you should create separate columns for them. Think about what you need at the beginning, but you can easily add one or two more columns later.
Tags like keywords shouldn't be stored in columns, because the amount is growing rapidly over time. That wouldn't make any sense. So for that, build a table with id and keyword in it and a link table with post_id and keyword_id. You could also omit the keyword_id and directly link post_id and keyword.
Make sure that both columns combined define the primary key, so you can not end up with a keyword stored several time to one particular post.
For attributes it can be the same. It is not a bad practice to create an attribute table with attribute_id, attribute_name and maybe more information and a link table attribute_id and post_id and content.
You can also easily enhance it to be multilingual by using attribute_ids.
Comments are the same, stored in a separate table with a link to a user and a post: comment_id, user_id, post_id, content and maybe parent_id, which can be a comment_id if you want comments to be commentable again.
That's it for a brief overview.