I'm creating a table named finishProducts that has the following columns:
product_id
product_name
product_unit
product_components_count
Each finish product may be composed of more than one components, these components should also be one of the finish products.
So it is like one to many relationship where one finish product may or may not have more than one components (Finish Products).
What is the best practice to create a table for such scenario?
One of the solution that i think is to add multiple rows for same finish product with different product components. See attached Image.
But this solution might not be the best one because in future i might have to add another column named Color for this table where i would have to apply the same one to many rule (one product can have multiple colors).
So i'm searching for a best possible solution.
Why not have two tables, one for products and one for components. Then have a one to many relation ship to the components.
product_id | product_name
--
12 | Epoxytile
Component_id | product_id | Component_name
--
1 | 12 | Expoxytile base
2 | 12 | Epoxytile grout
3 | 12 | Expsytile Silica
You can have however many components you need then. To query for them, just use
SELECT product_id, p.prouduct_name, c.compoent_name
FROM product p
INNER JOIN compoent c ON p.product_id = c.product_id
Related
I'm currently designing a relational database table in MySQL for handling multiple categories, representing them later in a tree structure on the client side and filtering on them. Here is a picture of how the structure looks like:
So we have a root element which is set by default. We can after that add children to it (Level one). So far a table structure in the simplest case could be defined so:
| id | name | parent_id |
--------------------------------
1 All Categories NULL
2 History 1
However, I have a requirement that I need to include another tree structure type (Products) in the table (a corresponding API is available). The records from the other table have their own id types (UUID). Basically I need to ingest them in my table. A possible structure will look like so:
| id | UUID | name | parent_id |
----------------------------------------------------------
1 NULL All Categories NULL
2 NULL History 1
3 NULL Products 1
4 CN1001231232 Catalog electricity 3
5 CN1001231242 Catalog basic components 4
6 NULL Shipping 1
I am new to relational databases, but all of these possible NULL values for the UUID indicate (at least for me) to be bad design of database table. Is there a way of avoiding this, or even better way for this "ingestion"?
If you had a table for users, with columns first_name, middle_name, last_name but then a user signed up and said they have no middle name, you could just store NULL for that user's middle_name column. What's bad design about that?
NULL is used when an attribute is unknown or inapplicable on a given row. It seems appropriate for the case you describe, i.e. when records that did not come from the external source have no UUID, and need no UUID.
That said, some computer science theorists insist that NULL is never appropriate. There's a decades-old controversy about whether SQL should even have a NULL.
The alternative would be to create a second table, in which you store only the UUID and the reference to the entity in your first table. Then just don't store rows for the other id's.
| id | UUID |
-------------------
4 CN1001231232
5 CN1001231242
And don't store the UUID column in your first table. This eliminates the NULLs, but it means you need to do a JOIN of the two tables whenever you want to query the entities with their UUID's.
First make sure you actually have to combine these in the same table. Are the products categories? If they are categories and are used like categories then it makes sense to have them in the same table, but if they have categories then they should be kept separate and given a category/parent id.
If you're sure it's appropriate to store them in the same table then the way you have it is good with one adjustment. For the UUID you can use a separate naming scheme that makes it interchangeable with id for those entries and avoids collisions with the other uuids. For example:
| id | UUID | name | parent_id |
----------------------------------------------------------
1 CAT000000001 All Categories NULL
2 CAT000000002 History 1
3 CAT000000003 Products 1
4 CN1001231232 Catalog electricity 3
5 CN1001231242 Catalog basic components 4
6 CAT000000006 Shipping 1
Your requirements combine the two things relational database are not great with out of the box: modelling hierarchies, and inheritance (in the object-oriented sense).
Your design users the "single table inheritance" model (one of 3 competing options). It's the simplest option in terms of design.
In practical terms, you may want to add a column to explicitly state which type of record you're dealing with ("regular category" and "product category") so your queries are more obvious to others.
We are building a web database system and we need to allow some products to be made of other products. For example combining 2 or more products as a new product. We are using CakePhp and MySQL.
Here is the data structure diagram of our database:
https://www.dropbox.com/s/ksv22rt45uv69k9/Data%20Structure%20Diagram.png
Would we need to have self referencing products table or create a new table?
You can do either. There are pros and cons to both. Either way you will need a cross reference table.
The cross reference table can refer itself.
products in item
+---------------------+----------------------------+------------+
| product_identifier | product_identifier_child | quantity |
+---------------------+----------------------------+------------+
| 1 | 1 | 1 |
| 2 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 2 | 1 |
+---------------------+----------------------------+------------+
On the bright side, this method means you only have one table of data and only one new cross reference table, and you can add new products as you see fit (along with multiple of the same products, say, with a gift basket). On the downside, your table will be trying to do two different things at the same time. Products that have other products in them may not have a model number. Also, how will you determine whether to check the inventory table? Are you going to have inventory for products that are made out of products, or would you sooner check stock on individual products in order to see if your combo products are in stock? The latter is much more flexible, and you can still reserve inventory this way. It just allows all of your inventory to be in the same unit scale in your inventory table.
To add more flexibility, you can create another table, base products, which has values only the building block products are going to have.
base products
+--------------------------+----------+--------------+
| base product identifier | brand | model number |
+--------------------------+----------+--------------+
You could then attach your inventories to your base products table, and your cross reference table would be products to base products.
The negative here is that now instead of two tables, you have three. However, I am a fan of more tables with fewer columns thanks to increased flexibility. Even if the table tasks are not completely different, letting each table specialize completely can make things a lot easier.
There are numerous ways to go but optimal situation is the one that requires no data duplication and no NULL values. Without stressing yourself out about getting all the way there, try to keep your NULL values out of indexed columns and make sure your name values are only showing up in one place.
Sorry if my question seems unclear, I'll try to explain.
I have a column in a row, for example /1/3/5/8/42/239/, let's say I would like to find a similar one where there is as many corresponding "ids" as possible.
Example:
| My Column |
#1 | /1/3/7/2/4/ |
#2 | /1/5/7/2/4/ |
#3 | /1/3/6/8/4/ |
Now, by running the query on #1 I would like to get row #2 as it's the most similar. Is there any way to do it or it's just my fantasy? Thanks for your time.
EDIT:
As suggested I'm expanding my question. This column represents favourite artist of an user from a music site. I'm searching them like thisMyColumn LIKE '%/ID/%' and remove by replacing /ID/ with /
Since you did not provice really much info about your data I have to fill the gaps with my guesses.
So you have a users table
users table
-----------
id
name
other_stuff
And you like to store which artists are favorites of a user. So you must have an artists table
artists table
-------------
id
name
other_stuff
And to relate you can add another table called favorites
favorites table
---------------
user_id
artist_id
In that table you add a record for every artist that a user likes.
Example data
users
id | name
1 | tom
2 | john
artists
id | name
1 | michael jackson
2 | madonna
3 | deep purple
favorites
user_id | artist_id
1 | 1
1 | 3
2 | 2
To select the favorites of user tom for instance you can do
select a.name
from artists a
join favorites f on f.artist_id = a.id
join users u on f.user_id = u.id
where u.name = 'tom'
And if you add proper indexing to your table then this is really fast!
Problem is you're storing this in a really, really awkward way.
I'm guessing you have to deal with an arbitrary number of values. You have two options:
Store the multiple ID's in a blob object in JSON format. While MySQL doesn't have JSON functions built in, there are user defined functions that will extract values for you, etc.
See: http://blog.ulf-wendel.de/2013/mysql-5-7-sql-functions-for-json-udf/
Alternatively, switch to PostGres
Add as many columns to your table as the maximum number of ID's you expect to have. So if /1/3/7/2/4/8/ is the longest entry, have 6 columns in your table. Reason this is bad: you'll have sparse columns that'll unnecessarily slow your tables.
I'm sure you could write some horrific regex to accomplish the task, but I caution on using complex regex's on enormous tables.
my rule of business is something like a used car/motobike dealership:
My table "stock" contains cars, so no two of the same products as each automobile belongs to a different owner.
Sometimes the owner has two cars that he wants to sell separately, but also wants to sell them together, eg:
Owner has a car and a motorcycle:
+----------------+
| id | Stock |
+----+-----------+
| 1 | car |
+----+-----------+
| 2 | motorcycle|
+----+-----------+
In case he wants to advertise or sell in two ways, the first would be the car for U$10.000 and motobike for U$5.000
But it also gives the option to sell both together for a lower price (car + bike U$ 12.000), eg:
+----+-----------+--------------------+-----------+
| id | id_poster | Stock | Price |
+----+-----------+--------------------+-----------+
| 1 | 1 | car | U$ 10.000 |
+----+-----------+--------------------+-----------+
| 2 | 2 | motorcycle | U$ 5.000 |
+----+-----------+--------------------+-----------+
| 1 | 3 | car | U$ 12.000 |
+----+-----------+--------------------+-----------+
| 2 | 3 | motorcycle | U$ 12.000 |
+----+-----------+--------------------+-----------+
This is the best way to do this?
My structure is already doing so (just as I believe to be the best way), I'm using foreign key and n:m, see my structure:
Ok, so if I'm understanding the question right, you're wondering if using a junction table is right. It's still difficult to tell from just your table structures. The poster table just has a price, and the stock table just has a title and description. It's not clear from those fields just what they're supposed to represent or how they're supposed to be used.
If you truly have a many-to-many relationship between stock and poster entities -- that is, a given stock can have 0, 1 or more poster, and a poster can have 0, 1 or more stock -- then you're fine. A junction table is the best way to represent a true many-to-many relationship.
However, I don't understand why you would want to store a price in poster like that. Why would one price need to be associated with multiple titles and descriptions? That would mean if you changed it in one spot that it would change for all related stock. Maybe that's what you want (say, if your site were offering both A1 and A0 size posters, or different paper weights with a single, flat price across the site regardless of the poster produced). However, there just aren't enough fields in your tables currently to see what you're trying to model or accomplish.
So: Is a junction table the best way to model a many-to-many relationship? Yes, absolutely. Are your data entities in a many-to-many relationship? I have no idea. There isn't enough information to be able to tell.
A price, in and of itself, may be one-to-one (each item has once price), one-to-many (each item has multiple prices, such as multiple currencies), or -- if you use a price category or type system like with paper sizes -- then each item has multiple price categories, and each price category applies to multiple items.
So, if you can tell me why a stock has multiple prices, or why a single poster price might apply to multiple stock, then I can tell you if using a junction table is correct in your situation.
Having seen your edit that includes your business rules, this is exactly the correct structure to use. One car can be in many postings, and one posting may have many cars. That's a classic many-to-many, and using a junction table is absolutely correct.
Not clear how the examples relate to your diagram because you use different terminology, but I think it's safe to say: If you want to store something like "this entity consists of orange, apple and pear" then the DB design you show is the correct way to do it. You'd have one poster entry, and three entries in the poster_has_stock pointing to the same poster and three elements in stock.
The structure which you're using is best solution in your case, no need to change, just 2 minor changes needed:
1. remove 2 indexes: fk_poster_has_stock_stock1_idx and fk_poster_has_stock_poster_idx, because they are primary keys already
2. stock_price field should use decimal data type (more precise)
You can read more about Decimal data type here
I think Your solution is nearly perfect. I think You may add "id" to "poster_has_stock" table. And of course change price type (it was written upper).
But You may consider second option with stock_id in poster table.
WHY?
-There should be no poster with no stock connected to it.
-In most cases there will be offers: one stock <=> one poster
This will allow You also to add as many dependend stocks to poster as You want.
You can also add poster_special_price DECIMAL (9,2) to poster table.
This will allow You easy to show:
price for stock item.
Special price for stock item with it's dependencies.
This will be also easier to manage in controller (create, update) - You will be adding poster already with stock, No transactions will be needed during adding new poster.
you may consider a new table that creates a relationship between the stock items such as:
stock_component
---------------
parent_stock_id
child_stock_id
child_qty
in this way, you can link up many children into one parent in the style of a bill of materials, then the rest of your links can continue to be simply related to stock_id of the appropriate parent.
I'm working on a restaurant CMS app. I have a many-to-many relationship between 2 tables, menu_sections and menu_items. The relationship is maintained with a table in between called menu_relationships.
As an example let's say the menu section called Snacks (menu_section_id = 1) contains a menu item called Pretzels (menu_item_id = 1) and the menu section called Desserts (menu_section_id = 2) contains a menu item called Ice Cream (menu_item_id = 2), but Ice Cream is also contained within another menu section called Kids Food (menu_section_id = 3). So there would be 3 rows in the menu_relationships table to map out these 3 relationships. The relationship table would look like this:
---------------------------------------
| menu_section_id | menu_item_id |
|=====================================|
| 1 | 1 |
|-------------------------------------|
| 2 | 2 |
|-------------------------------------|
| 3 | 2 |
---------------------------------------
So far so good.
I want to generate a result set that will return the names of all menu items except for menu items with a given menu_section_id. So to return the menu item names, I have a join on the menu_items table. Here's the SQL:
SELECT menu_section_id, menu_items.menu_item_id, menu_item_name
FROM menu_relationships
JOIN menu_items
ON menu_items.menu_item_id = menu_relationships.menu_item_id
WHERE menu_section_id != 2
The result set which will give me a row for each relationship that doesn't contain a given menu_section_id. With the example data I would be getting 2 rows back from the relationship table:
-----------------------------------------------------------
| menu_section_id | menu_item_id | menu_item_name |
|======================================|==================|
| 1 | 1 | Pretzels |
|--------------------------------------|------------------|
| 3 | 2 | Ice Cream |
-----------------------------------------------------------
But what I want is to exclude the menu item altogether from the result set, if it has ANY relationship to the specified menu_section_id. In other words, in the case of this example , I only want to return rows for menu items that have no relationship mappings at all to a menu_section_id of 2, I only want to return the Pretzels row.
I've tried various things with GROUP BY and HAVING using the bit_xor() aggregate function, but so far no luck at all in getting what I want.
I probably could have taken less time to explain that but I wanted it to be a clear as I can make it. I hope it is. Can anyone help?
This is a wonderful case for the use of LEFT OUTER JOIN because it includes all rows from your left-hand table and matches where it can, returning NULL for any non-match.
Building on Mark Breyer's sample query from above, see this example:
SELECT R.menu_section_id, I.menu_item_id, I.menu_item_name
FROM menu_items AS I
LEFT OUTER JOIN menu_relationships R on (R.menu_item_id=I.menu_item_id) AND (R.menu_section_id = 2)
The mysql optimizer may actually rewrite this as a subquery - i'm not an optimization expert by any means - I'd take a look at the way your indexes are built and see if this type of join makes sense for your schema. I'd also test to see if it's actually faster because it's actually less semantic.
There are many ways to do this. Here is one example using WHERE ... NOT IN (...):
SELECT
R.menu_section_id,
I.menu_item_id,
I.menu_item_name
FROM menu_items AS I
JOIN menu_relationships AS R
ON R.menu_item_id = I.menu_item_id
WHERE I.menu_item_id NOT IN
(
SELECT menu_item_id
FROM menu_relationships
WHERE menu_section_id = 2
)
I would use a subquery for this, getting me every menu_item_id which has the menu_section_id 2 and then using NOT IN. Here you go:
SELECT menu_section_id, menu_items.menu_item_id, menu_item_name
FROM menu_relationships
JOIN menu_items
ON menu_items.menu_item_id = menu_relationships.menu_item_id
WHERE menu_relationships.menu_item_id NOT IN (
SELECT menu_item_id
FROM menu_relationships
WHERE menu_section_id = 2
);
I was going to suggest a subquery a well, except that I wanted to mention that subqueries can dramatically affect performance on your site. You may want to consider options for caching to avoid serious load time hangups due to things like this.
In most cases you'll be ok, but if you're only showing us part of the issue and just not mentioning the irrelevant details then you could very well be building a site where you run 100 of these queries on a page, for example, because someone mentioned it here without mentioning the compounded overhead things like this can result in...
Like I said though, you'll probably be fine. Just don't do a subquery within a subquery unless you want to restart your server.