I am going to make a website and before that I am going to make a database table. The problem is how to do it correctly. Sorry, but I am new to PHP and Mysql. I only have a definite number of categories, so this is my DB view:
--------------------
Video_name Varchar
Video_loc Varchar
cat1 Boolean
cat2 Boolean
cat3 Boolean
cat4 Boolean
cat5 Boolean
cat6 Boolean
cat7 Boolean
--------------------
I kept it like this because 1 video might belong to 2 or more categories. But it will take a lot of space in long term. If a video belongs to cat2 & cat5 then the boolean will have the value "1". But others will also have the value "0" and this is a waste of space.
How can I do it the right way? BTW I have seen Wordpress, it gives the categories a unique ID then on the main table it specifies multiple ids for multiple categories like e.g.: it keeps it like:
-----------------------
id | title | category |
1 | Lorem | 2,4,8,16 |
2 | Epsum | 2,9,8,20 |
3 | Losum | 2,4,9,5 |
4 | Eprum | 2,10,8,1 |
-----------------------
I don't get how it did it like that. Can anyone tell me how to do it like this or any better idea than mine?
Generally it is a "no no" to store structured data within a single column in a table. The Wordpress example does exactly that; it stores a comma separated list of categories in the category column. For that reason I would not recommend using that schema.
The "right" way to do this is to have a table for videos and another table for categories. The relationship between videos and categories is managed by a third table which maps the video to a category and vice versa. There will be multiple entries in this video-to-category table - one for each category that a video can be assigned. Something like this:
table: video
----------------
id int
name varchar
location varchar
----------------
table: category
----------------
id int
name varchar
----------------
table: video_category
---------------------
video_id int
category_id int
---------------------
Another way would be to use a bit field for the categories. Your video table would then have just a single column for all categories with bits set to 1 for those categories to which the video belongs, and 0 for those that it does not. This is an option if storage space is very important to you, however, it is less flexible than using 3 tables, and I recommend the latter approach.
Generally you use a 3rd table with the relationship between the video and category. So you'd have a categories_videos table which has id, category_id, and video id
You can do joins to get all categories related to material, but this is more advanced MySQL. Either start reading the MySQL documentation or pickup a framework that helps you with all this and makes it easier, I always recommend Cakephp.
Related
I am creating a video player application with php and mysql.
The application has videos that are gathered in playlists like this:
Playlists table:
+----+------------------+------+
| id | name | lang |
+----+-------------------------+
| 1 | Introduction | 1 |
+----+-------------------------+
Videos table:
+----+--------------+-------------+
| id | name | playlist_id |
+----+--------------+-------------+
| 1 | Video1 | 1 |
| 2 | Video2 | 1 |
+----+--------------+-------------+
It worked fine until now, because I need to build a searcher that finds videos depending on its name and language.
I though of creating another field called lang in the videos table, but then I realize that this maybe would contradict the normalization database rules. Because I would be repeating unnecessary information.
What can I do to select the videos without creating another field? Or do I need to create a new one with the repeated information?
EDIT:
JOIN LEFT both tables is not a solution, because I maybe add in the future a new table that links to playlists such as courses.
You can make LANGUAGE_ID COLUMN in Videos table,which will foreign key references to Playlists.lang .
Try above solution.
Hope this will help you.
You need to be clear about what attribute you want to assign to which entity (playlist, video or possibly course). You can assign language ids to both, playlist and video list items independently. Who is to say that you are not allowed to include a video with a language id of 2 in a playlist that carries a language id of 1? (This could, for example be a video in a foreign language that you want to appear in a playlist of your own language).
To search for suitable items you should then definitely use some kind of join (on video.playlist_id=playlist.id). The resulting table will contain both, video.language_id and playlist.language_id, which is not a case of having redundant information, as I have tried to explain above since they refer to different entities.
Existing System:
I have a mySQL database that stores category related information for approximately 200 different unique users. The information being stored and retrieved for each user is in the hierarchy of
imageCategories
> Parent Category 1
> Child Category 1 : "45,19,3,4,8"
> Child Category 2 : "17,1,99"
> ... etc
> Parent Category 2
> Child Category 1 : "83,6"
> Child Category 2 : "19,74,26"
... etc
> etc
The string value of each child category is a series of comma-separated ids which reference descriptions (on a separate table) stored under that child category. I store all of this as an array in a column for each user by means of a json_encoded string in the form of:
{"Parent Category 1":{"Child Category 1":["45,19,3,4,8"],"Child Category 2":["17,1,99"]},"Parent Category 2":{"Child Category 1":["83,6"],"Child Category 2":["19,74,26"]}}
The system works by retrieving this json_string when a user logs and decoding it to a session array. Whenever any changes are made to it, it's reencoded to a json string, saved to the database and the session array is updated to reflect this. This works fine. While my research way back when made me do so, I was never quite sure if storing a multi-dimensional array in mySQL is good best practise. What I do know is that this keeps organising it quite stress-free and I haven't noticed it causing a lot of overhead, which is not to say that it doesn't.
The conundrum:
What I want to do now is add a string description to each Child Category in the database. Potentially to each Parent Category later but baby steps first.
I was initially going to start a third dimension for the overall array. Instead of:
"Child Category Key" : "id string"
I would change it to:
"Child Category Key" : ["id string", "description string"]
or:
"Child Category Key" : ["id string", id for description on another table]
I don't see an issue with either, but I'm wondering if im veering way off best practises. Should I be creating a new table for the entire category structure, rather than storing all of it as a json string in a column with other user settings (it's never going to get too unwieldly in terms of character length). The current structure is quite easy to get my head around and I wouldn't necessarily jump to a solution that would provide minimal overhead benefits if it's structure makes managing the database unecessarily complicated (keep in mind some of us aren't naturals at this and our brains process this kinda structure a little slower than others).
Design Requirements:
I may miss out on describing specifics needed as I'm unsure what the most pertinent information is from what's relevant. I can elaborate where needed. What seems the most important design requirement is that each user has unique category keys and values. They can only be in the form of parent > child > csv of ids but each user will have custom key titles and a different number of each. The order of each is also essential.
I'm currently running on a server with ssd disk, 1gb of memory and a single 2ghz core from an Intel hexcore. Requests to the database are primarily retrieving the categories on both a front and backend. The majority use little traffic so nothing has been too taxing apart from occasional spikes. I will upgrade when I see a bottleneck approaching. Just trying to use what I have as efficiently as possible at the moment and keep best practices in play.
Database Structure:
Right now my table structure is in the form of (omitting other columns not relevant to the question):
Table usersettings:
+-----+----------------------+-----+
| id | imageCategories | ... |
+-----+----------------------+-----+
| 1 | {"Parent Category... | ... |
| 2 | {"Parent Category... | ... |
| 3 | {"Parent Category... | ... |
| ... | | |
+-----+----------------------+-----+
Table users:
+-----+----------------------+---------+--------+
| id | username | cluster | server |
+-----+----------------------+---------+--------+
| 1 | johndoe | 1 | 1 |
| 2 | katedoe | 1 | 1 |
| 3 | ellendoe | 1 | 1 |
| ... | | | |
+-----+----------------------+---------+--------+
Table descriptions_0001:
+-----+---------+---------------+-----+
| id | title | descriptions | ... |
+-----+---------+---------------+-----+
| 11 | Title 1 | Description 1 | ... |
| 56 | Title 2 | Description 2 | ... |
| 78 | Title 3 | Description 3 | ... |
| ... | | | |
+-----+---------+---------------+-----+
There is an equal row for every usersettings entry in users with matching ids. So their username etc. can always referenced from usersettings by knowing its own id number. Currently I only have one database but in an attempt to future proof it to some degree I store descriptions in a table with an index in its name and each user has a cluster number value as well as a server number value. Each user has, on average, about 100 descriptions row so this is coming to 20,000 rows at the moment. When this is creating a bottleneck I'll start a descriptions table 0002, and later a second server should it be needed. Perhaps I'm naive in my workflow but it seems like it should help.
Summary:
So in summary, should I adapt my categories array to store a string description for child categories by:
Making the child categories key have an array value rather than the
current string value that contains the current string value and an
additional string description.
Like 1 but make the string description an id number that references
a string on a new table
Look at not using a json encoded array at all and move the entire
category structure into its own table
Create a table for parent categories, one for child categories and one for the csv contents. Include a description column (per the conundrum above) and an order column (essential, per the design requirements above) in each - or is there a better method of storing order than retrieving and updating the order column for each relevant row when the table will contain unique category information for multiple users? It sounds like it may require a lot of overhead.
I ended up going for a solution somewhat similar to (4). I also better appreciate the importance of describing the design requirements now as what led me to this decision was the realisation that it was more efficient in processing (I believe?) and simpler to comprehend working with select levels of a hierarchy at a time.
For example, If I'm dealing with all descriptions under parent category 2, child category 1, I just fetch or insert all descriptions in a description table with a shared identifier, rather than dealing with a multidimensional array that contains all hierarchies. The latter made organising users in the db easier but the categorisation was becoming large enough that I decided it did warrant separate tables for each level of the hierarchy. There's enough situations where I'm working with only an isolated level of the categorisation hierarchy that putting the entire categorisation into a single md array felt like the poorer choice.
In terms of overhead difference, I'm unsure for now. There's less sorting of arrays happening in php to isolate data I need but there's far more calls to the db.
My hesitation in understanding the design requirements (and still not giving a thorough answer on this) is that I'm new to large user databases and am not good at forecasting the needs. I'm designing it in such a way that it feels scalable to me and so, again, the table for each level of the hierarchy feels the least cumbersome (after the cumbersome set up - I'm currently redoing tonnes of code to make functions work with the new set up) and more scaleable as needs change.
I am finalizing a comments system and was with a doubt.
I have a table for blogs and one for news, and they accept comments.
My comments table receives the text and the id.
I wonder if I need to (or should I) go through some sort of reference to know where the comment comes from.
table comment
id | id_content | text | ref
1 | 1 | test | blog
2 | 1 | test | news
thanks
depending on the number of comments you expect to receive there are two ways of doing this ...
1 - parent_tbl, parent_id - in one big comment table
2 - two tables for comments with a parent_id - one for each primary table
either way you need to index properly, the second will always work faster, but it doesn't expand well if you say add "press_releases" now you have to duplicate code, tables, what not.
I am planning designing a PHP MySQL database for a local museum's photo gallery.
One thing that terrifies me now is how to implement saving multiple keywords for a single image for items where more than one technic or material was used to design them, e.g.
PAINTING TECHNICS:(liner, wiping, scumbling), MATERIAL USED: (oil, canvas,).
Ideally, I would have to use the select option lists to save them for each record. But if I want to save two or more of the words from the same list, I cant.
Do you have any suggestions I might consider?
joseph
You will need to implement a one-to-many relationship between your image table and your keyword table. One image can have many keywords. Each row in your keyword table will need to reference a row in the image table through a foreign key. For example:
images
id | asset
---------------
1 | image1.png
2 | image2.png
keywords
id | image_id | keyword | category
-----------------------------------------------
1 | 1 | liner | painting techniques
2 | 1 | wiping | painting techniques
3 | 1 | scumbling | painting techniques
3 | 2 | oil | material used
Or something along those lines. This is how you allow one row (an image) to be associated with many rows (keywords) in a different table.
For each keyword submitted, you would add another row to the keywords table, making sure to reference the associated image.
Take a look at the items table below, as you can see this table is not normalized. Name should in a separate table to normalize it.
mysql> select * from items;
+---------+--------+-----------+------+
| item_id | cat_id | name | cost |
+---------+--------+-----------+------+
| 1 | 102 | Mushroom | 5.00 |
| 2 | 2 | Mushroom | 5.40 |
| 3 | 173 | Pepperoni | 4.00 |
| 4 | 109 | Chips | 1.00 |
| 5 | 35 | Chips | 1.00 |
+---------+--------+-----------+------+
This table is not normalize because on the backend Admin site, staff simply select a category and type in the item name to add data quickly. It is very quick. There are hundreds of same item name but the cost is not always the same.
If I do normalize this table to something like this:
mysql> select * from items;
+---------+--------+--------------+------+
| item_id | cat_id | item_name_id | cost |
+---------+--------+--------------+------+
| 1 | 102 | 1 | 5.00 |
| 2 | 2 | 1 | 5.40 |
| 3 | 173 | 2 | 4.00 |
| 4 | 109 | 3 | 1.00 |
| 5 | 35 | 3 | 1.00 |
+---------+--------+--------------+------+
mysql> select * from item_name;
+--------------+-----------+
| item_name_id | name |
+--------------+-----------+
| 1 | Mushroom |
| 2 | Pepperoni |
| 3 | Chips |
+--------------+-----------+
Now how can I add item (data) on the admin backend (data entry point of view) because this table has been normalized? I don't want like a dropdown to select item name - there will be thousands of different item name - it will take a lot of of time to find the item name and then type in the cost.
There need to be a way to add item/data quick as possible. What is the solution to this? I have developed backend in PHP.
Also what is the solution for editing the item name? Staff might rename the item name completely for example: Fish Kebab to Chicken Kebab and that will effect all the categories without realising it. There will be some spelling mistake that may need correcting like F1sh Kebab which should be Fish Kebab (This is useful when the tables are normalized and I will see item name updated every categories).
I don't want like a dropdown to select item name - there will be thousands of different item name - it will take a lot of of time to find the item name and then type in the cost.
There are options for selecting existing items other than drop down boxes. You could use autocompletion, and only accept known values. I just want to be clear there are UI friendly ways to achieve your goals.
As for whether to do so or not, that is up to you. If the product names are varied slightly, is that a problem? Can small data integrity issues like this be corrected with batch jobs or similar if they are a problem?
Decide what your data should look like first, based on the design of your system. Worry about the best way to structure a UI after you've made that decision. Like I said, there are usable ways to design UI regardless of your data structuring.
I think you are good to go with your current design, for you name is the product name and not the category name, you probably want to avoid cases where renaming a single product would rename too many of them at once.
Normalization is a good thing but you have to measure it against your specific needs and in this case I really would not add an extra table item_name as you shown above.
just my two cents :)
What are the dependencies supposed to be represented by your table? What are the keys? Based on what you've said I don't see how your second design is any more normalized that your first.
Presumably the determinants of "name" in the first design are the same as the determinants of "item_name_id" in the second? If so then moving name to another table won't make any difference to the normal forms satisified by your items table.
User interface design has nothing to do with database design. You cannot let the UI drive the database design and expect sensible results.
You need to validate the data and check for existence prior to adding it to see if it's a new value.
$value = $_POST['userSubmittedValue']
//make sure you sanitize the variable (never trust user input)
$query = SELECT item_name_id
FROM item_name
WHERE name='$value';
$result = mysql_query($query);
$row = mysql_fetch_row($result);
if(!empty($row))
{
//add the record with the id from $row['item_name_id'] to items table
}
else
{
//this will be a new value so run queries to add the new value to both items and item_name tables
}
There need to be a way to add item/data quick as possible. What is the
solution to this? I have developed backend in PHP.
User interface issues and database structure are separate issues. For a given database structure, there are usually several user-friendly ways to present and change the data. Data integrity comes from the database. The user interface just needs to know where to find unique values. The programmer decides how to use those unique values. You might use a drop-down list, pop up a search form, use autocomplete, compare what the user types to the elements in an array, or query the database to see whether the value already exists.
From your description, it sounds like you had a very quick way to add data in the first place: "staff simply select a category and type in the item name to add data quickly". (Replacing "mushroom" with '1' doesn't have anything to do with normalization.)
Also what is the solution for editing the item name? Staff might
rename the item name completely for example: Fish Kebab to Chicken
Kebab and that will effect all the categories without realising it.
You've allowed the wrong person to edit item names. Seriously.
This kind of issue arises in every database application. Allow only someone trained and trustworthy to make these kinds of changes. (See your dbms docs for GRANT and REVOKE. Also take a look at ON UPDATE RESTRICT.)
In our production database at work, I can insert new states (for the United States), and I can change existing state names to whatever I want. But if I changed "Alabama" to "Kyrgyzstan", I'd get fired. Because I'm supposed to know better than to do stuff like that.
But even though I'm the administrator, I can't edit a San Francisco address and change its ZIP code to '71601'. The database "knows" that '71601' isn't a valid ZIP code for San Francisco. Maybe you can add a table or two to your database, too. I can't tell from your description whether something like that would help you.
On systems where I'm not the administrator, I'd expect to have no permissions to insert rows into the table of states. In other tables, I might have permission to insert rows, but not to update or delete them.
There will be some spelling mistake that may need correcting like F1sh
Kebab which should be Fish Kebab
The lesson is the same. Some people should be allowed to update items.name, and some people should not. Revoke permissions, restrict cascading updates, increase data integrity using more tables, or increase training.