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.
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.
I made a firm to add a user to my database now I want to have two tables. One table keeps track of the languages the user knows and the other table the design software the user uses.
Would I create 3 tables (profile, languages, software) each with an I'd field and when I add a user add a row to each table?
As you begin to add several many-to-many relationships, you need more tables to 'link' the information together. Here's how I would tackle the problem:
Note The IDs should all be unique indexed columns. Consider using AUTO_INCREMENT.
Table 1: Contains user's profile information
| ProfileID |UserInfo |
|=======================|
| 0 | Info |
|-----------------------|
| 1 | Info2 |
|-----------------------|
Table 2: Stores the possible languages
|LanguageID |LanguageName|
|========================|
| 50 | Python |
|------------------------|
| 51 | Java |
|------------------------|
and so on...
Table 3: Stores the Profile links to the languages
|ProfileID |LanguageID |
|========================|
| 0 | 50 |
|------------------------|
| 0 | 51 |
|------------------------|
| 1 | 50 |
|------------------------|
Every time you wanted to add a language to a user's profile, you'd create an entry in this table.
You would add two more tables for the software a user knows. One table for all the possible types of software, and another to store the links.
When you want to retrieve the information, you would do an operation such as the one below:
SELECT * FROM Table3
LEFT JOIN Table2
ON Table3.LanguageID = Table2.LanguageID
WHERE ProfileID = [TheProfileIDToSearch]
This structure uses JOIN to link tables together to return information from several tables at once. Here is a W3Schools quick explanation about SQL JOINS.
I'm wondering if there's a best practice when it comes to having multiple many-to-many relationships between the same tables.
Currently I have a many-to-many relationship between user and item for the items that users have created.
---------------------
| user_id | item_id |
---------------------
| 1 | 3 |
---------------------
I'd like to create another junction table for user and item to reference their watchlist. Should I create separate many-to-many tables?
user_item_inventory user_item_watchlist
--------------------- ---------------------
| user_id | item_id | | user_id | item_id |
--------------------- ---------------------
| 1 | 3 | | 2 | 3 |
--------------------- ---------------------
OR should I create one many-to-many table that has a many-to-one relationship with a user_item_type table?
user_item user_item_type
------------------------------- ------------------
| user_id | item_id | type_id | | id | name |
------------------------------- ------------------
| 1 | 3 | 1 | | 3 | inventory |
------------------------------- ------------------
| 2 | 3 | 2 | | 2 | watchlist |
------------------------------- ------------------
While the decision ultimately rests on just how conceptually different inventory and wishlists are, based on prior experience, I would suggest using separate tables.
Currently, you have no additional data attached to either the inventory or watchlist, but that will not necessarily be the case in the future. Without knowing more details about the inventory and watchlist, it's hard to make predictions, but as soon as you want to start tracking additional data on an inventory relation vs. a watchlist relation, having separate tables will make things much simpler. As soon as you want to add columns that only pertain to one of your types of association, you'll want to have separate tables.
As has been pointed out in the other answer, having separate tables is certainly faster from a pure data storage and retrieval standpoint: you'll have one less column/index to populate/filter by. And if your inventory/wishlist associations table becomes "large", those extra type_id references will start to add up to something significant. (It won't matter for smaller sizes, but besides the obvious disk storage factors, more data requires more memory and more cache to manage, especially when indexes are involved.)
Separate tables would be a complication if you need to know all the items a user has an interest in (the combination of inventory, watchlist, and any other similar tables you might create), but if that is an actual need, then you could generate that list easily with a UNION query on all of the tables. (You could even create another table that contains a copy of all the user - item references as a performance enhancement if necessary.)
It depens on how do you want to use these data. If they are logically separated and there is no releations between them, then you can use two tables.
If you're going to display inventory and watchlist records, in some module, and you want only distinguish type of records, then you can use one table with type of record.
It is clear that for database engine, it is better to do
SELECT * FROM user_item_inventory
reather than
SELECT * FROM user_item WHERE type_id = 1
I'm working on a website which will be like a marketplace where a registered seller could sell different kind of items. For each item there are common attributes and optional attributes. Take a look to the following, I'll try to explain.
Scenario
The seller add a new item (e.g. iPhone 6 16 gb black)
He builds the insertion specifying item attributes (e.g. price, shipping price, condition, images, description, etc..). This kind of attributes are required and common for any item.
Once all required attributes are filled, the seller have the ability to specify other kind of attributes that are related only with that item (e.g. RAM, capacity, size, weight, model year, OS, number of cores, etc..). This kind of attributes are optional. The seller specify key (e.g. capacity) and value (e.g. 16 gb) and them are related only for that single item. Another iPhone 6 16 gb black sold by another seller may have different attributes.
Actually we have a table called items which contains all the items for sale, and another table called item_attr which contains common item attributes. So an item could be related to 0, 1 or more optional attributes.
We are working on two kind of approaches to store optional values for each item, but both could bring problems.
Case A
Create a new table called item_additional_attr where each record
will represents an additional attribute for a single item. There will
be a one-to-many relationship between items and
item_additional_attr. This seems to be the most "database-friendly" solution, but I'm worried about the size of this
table could have. If items contains 100.000 records and each
item is related to an average of 5 optional attributes,
item_additional_attr will contains 500.000 records. Of course that will be a huge table.
Case B
Create a new field type TEXT or BLOB into item_attr called
optional_attributes. This field will contains an array of optional attributes and will be handled in PHP. Of course the array will be
stored as serialized or json encoded. I think this kind of approach could bring problems with some queries, but it could be handled without problems in PHP.
I'm giving priority to webserver/db performance, but I would also avoid problems with queries. Moreover additional attributes will be used only to show technical specs in a table, never for filtering/sorting. So, in your opinion, what is the best way to achieve that?
You may want to try using EAVs (entity attribute value) tables. Basically you will maintain several tables. One table should store the list of items. Other tables should maintain attributes that all have similar data types. I created a simple schema to demonstrate:
+---------+------------+
| item_id | item_name |
+---------+------------+
| 1 | Cell Phone |
| 2 | Shirt |
+---------+------------+
2 rows in set (0.00 sec)
+---------+--------------+----------------+-----------------+
| item_id | attribute_id | attribute_name | attribute_value |
+---------+--------------+----------------+-----------------+
| 1 | 2 | storage | 8GB |
| 1 | 3 | color | Gray |
| 2 | 4 | size | XL |
| 2 | 6 | shirt_color | Red |
+---------+--------------+----------------+-----------------+
4 rows in set (0.00 sec)
+---------+--------------+----------------+-----------------+
| item_id | attribute_id | attribute_name | attribute_value |
+---------+--------------+----------------+-----------------+
| 1 | 2 | price | 49 |
+---------+--------------+----------------+-----------------+
1 row in set (0.00 sec)
The first table is a list of items. The second table is a list of the items' attributes of type varchar. The third table list items' attributes of type int. This will allow a scalable database that disperses attributes to multiple tables. The only draw back is the amount of join you will need to do in order to get an item and all of its attributes. A textual caching scheme could be used via php in order to store item information for an increase in performance.
I have one table GAMES and another PLAYERS. Currently each "game" has a column for players_in_game but I have nothing reciprocating in the PLAYERS table. Since this column is an array (Comma separated list of the player's ID #s) I'm thinking that it would probably be better to have each player's record also contain a list of the games they are a member of. On the other hand, duplicating the information in two separate tables might actually require more DB calls.
For perspective, there aren't likely to be more then a dozen players in a game (generally 4-6 is the norm) but there could potentially be a large number of games.
Is there a good way to figure out which would be more efficient?
Thanks.
Normalization is generally a good thing. Comma delimited lists in tables is a sign that a table is in desperate need of a foreign key. If you're worried about extra queries, check out JOINING
dbo.games
+----+----------+
| id | name |
+----+----------+
| 1 | war |
| 2 | invaders |
+----+----------+
dbo.players
+----+----------+---------+
| id | name | game_id |
+----+----------+---------+
| 1 | john | 1 |
| 2 | mike | 1 |
+----+----------+---------+
SELECT games.name, count(players.id) as total_players FROM games INNER JOIN players ON games.id = players.game_id GROUP BY games.name;
Result:
+-----------+--------------+
| name |total_players |
+-----------+--------------+
| war | 2 |
| invaders | 0 |
+-----------+--------------+
Sidenote: Go Hokies :)
Oh god, please don't use CSVs!! I know it's tempting when you're new to SQL, but it becomes unqueryable...
You need 3 tables: games, players, and players_in_games. games and players should each have a primary auto-incrementing key like id, and then players_in_games needs just two fields, player_id and game_id. This is called a "many to many" relationship. A player can play many games, and a game can have many players.
The right answer is a table called PlayersInGames that has a player id and a game id per row.
I would create a third table that links the players and games. Your comma-delimited list is effectively a third table, but parsing your list is almost certainly going to be less efficient than letting the database do it for you.
Ask yourself what happens if you remove a row from the GAME table. Now you'll have to loop over all the PLAYER rows, parse the list, figure out which ones contain a reference to the removed GAME, and then update all the lists.
Bad design. Let SQL do what it was born for. The query will be fast enough if you index it properly. Micro-optimizations like this are the wrong approach.