What are the ways to model multivalued M : N relationship? - mysql

I am working on the project that requires multivalued M : N relationship.
For eg.
There is a list of products in the Products table.
The user can purchase 1 or more products and are maintained in the table Orders. Along with this information, there is one more table that maintains analytical information.
This table should contain the hard coded data like. If the order contains product 1 and product 2 then does product 3 and product 4 also appeared in the user's order. These are basically hard coded rules
actual products | expected products
1,3 | 2,4
5,6,7,8 | 3,4
Now from these tables, I need to find information like if user's order number 1 had products like 1 and 3 then return 2 and 4.
I need suggestions as to how to describe this multivalued M to N relationship. If there are any other options other than RDBMS feel free to suggest. Thanks

You could create three additional tables:
ProductSet(productset_id) - Stores product sets headers(one row from your sample)
ProductSetPart(productset_id,product_id) - Stores required products to make set, in your case column actual product
ProductSetAdditional(productset_id,product_id) - stores expected products.
Having given Order we can detect which additional products should be added.
EDIT: sample added
Example query that return list of Sets that are fulfilling requirements:
SELECT psp.productset_id FROM
ProductSetPart psp LEFT JOIN
OrderLines ol
ON
psp.product_id=ol.product_id
GROUP BY
psp.productset_id
HAVING
-- trick - COUNT(*) will return count of all products required by aggregatet set
-- COUNT(psp.product_id) will count only not null products
-- (which will be null if they aren't in order line)
-- so if all product sets are in order line then we know,
-- that this set requirements are full filled
COUNT(*) = COUNT(psp.product_id)

Related

Polymorphic relation use cases with Laravel - Design Database

I try to design my database and I get confuse.
In my app, an user belong to a group and this group may have multiple stocks of only one type of equipement.
Those stocks can be of two types:
Stock of power lines
Stock of windturbine
Each stock has an identifier representing the area.
Each stock has multiple equipements.
So, to summarize :
User A belongs to group A.
Group A has :
Windturbine1 which has 5 individual windturbines
Windturbines2 which has 10 individual windturbines
User B belongs to group B.
Group B has :
power_lines1 which has 10 individual powerlines
I tried to represent this scheme like this :
However, I'm not totally convinced. I'm not sure if the stock table need to be polymorphic with windturbine_area and power_line_area.
Any insights on this please ?

Which relationship model to use for storing a value that depends on other values?

The task that I have got:
Implement Product Discount functionality, where the amount of Discount depends on different conditions, for example:
Amount of Discount depends on Product Category (Phone, TV, PC);
Amount of Discount depends on Product Manufacturer (Apple, Samsung, Sony);
Amount of Discount depends on Customer Type (Registered/Guest);
etc.
Assume, that we need to cover only first condition, where the Discount amount per Manufacturer - I think this is a pure example of 1 to 1 relationship, where for each Manufacturer defined their own discount.
From the DB schema point of view, we can easily implement this part in 2 ways:
One Table MANUFACTURER_DISCOUNT with 2 Columns: MANUFACTURER_NAME (type ENUM) and DISCOUNT_AMOUNT (type: LONG);
Or with 2 Tables MANUFACTURER (MANUFACTURER_NAME, ID) and DISCOUNT (DISCOUNT_AMOUNT, MANUFACTURER_ID);
But what I have to do in the case when I have more than 1 criteria (discount per manufacturer) only?
How can I properly build the structure of my tables?
Do I need just to extend the table that I described as option 1 with additional columns like PRODUCT_CATECORY, CUSTOMER_TYPE or possible more elegant and correct solution exists?
Each discount should be its own table.
Then the amount of discount query becomes something like:
SELECT IFNULL(cd.discount, 0) + IFNULL(md.discount, 0) + IFNULL(custd.discount, 0) as discount
FROM product p
LEFT JOIN category_discount cd
ON p.category = cd.category
LEFT JOIN manufacturer_discount md
ON p.manufacturer = md.manufacturer
LEFT JOIN customer_discount custd
ON p.customer_type = custd.customer_type
Note the JOINs are more important here than the exact calculation on the discount, just remember NULL is a not found value and need to be accounted for.
Keep tables for a single purpose. Putting multiple discount types could just get messy as you'd need multiple rows. Multiple tables with one to one relationships also end up being an unnecessary complication.
When in doubt about table structures, start to write out the queries you need on those tables. It usually becomes obvious which table structure results in simple queries at that point.

Advanced Search Functionality - SQL

i'm working on an advanced search functionality on my website.
Basically data I'm working on is stored within two tables.
First table contains basic information about the product (1 row = 1 product so it's unique).
Table structure may look like this:
id, title, description
The second table contains more information about the product. The product may but don't have to have any rows here. However, one product may store in the second table a few rows. What's more - data in the second table should be used to the advanced search functionality. Table structure may looks like this:
id, item_id (from table 1), value_id (from another table), value
I want to select only these products (table 1) which has specified value_id (from column 2):
... WHERE table1.item_id = 5 AND table2.value_id = 1000
As I mentioned before - table 2 may but doesn't have to contains any rows connected by item_id with the table 1.
I've tried to use JOIN/LEFT JOIN function in SQL but in this case when the product has 3 rows in the table 2 - a query result returns 3 rows instead of 1 or 0 (if not found any results).
How can I handle that?
You want to select products. So select from the product table. You want to select only those for which exists a certain attribute. So create an approriate WHERE clause. As you want to look up data in another table, you could use EXISTS or IN.
select *
from items
where id in (select item_id from item_values where value_id = 1000);

Self inner join to get single record

I have an SQL table data as follow
I want to display single record for product
example
90792 Amlaan-Hi-Power .............. Show only 1 record when there are 2 record
90793 Amlaan-Neutral .............. show only 1 record when there are 2 record
90794 Amlaan-Phosphate free .........show only 1 record when there are 2 record
90801 Acetone .......................show only 1 record when there are 2 record
90901 Acetanilide ...................show only 1 record when there is 1 record
Can I do this using Inner join
I know
select distinct product from product ORDER BY `product`.`product` DESC
will select distinct (unique) product code and that to only one field i.e. product but confused how to get other information using SQL statement
but results in duplicate records or same table...........................
It looks like your duplicate rows vary by the quantity of product in the package.
You can display just the product and name with
SELECT DISTINCT product, name
FROM product
If you want to deal with the quantity as well, that's a little trickier. This might work: it will put all product codes on one line.
SELECT product,
GROUP_CONCAT(product_code ORDER BY product_code) product_codes,
name
FROM product
GROUP BY product, name
Self join doesn't make a whole lot of sense for this application.
Use group by option for such purposes.
SELECT product,GROUP_CONCAT(product_code SEPERATOR '|') AS product_code,name FROM Table GROUP BY NAME
It will show only one record for duplicate names.
The multiple enteries of product code will seperated by | .

SELECT all items in common between two users on FOUR tables

I have now four tables:
item_to_list (to store the relations between list and item)
| item_to_list_id | list_id | item_id |
-----------------------------------------
item_tb
| item_id | item_name |
-----------------------
list_tb (is a list of items that belong to a unique user, a list can't be owned by two users)
| list_id | list_name | user_id |
---------------------------------
user_tb
| user_id | user_name |..etc..
-------------------------------
An item can belong to one or more list.
A list can belong to only one user and a user can have one or more lists...
Different lists can have same items in common (think a grocery list that you buy every week the same items)
basically imagine my website is an e-commerce, the list is an order, and i want to know how many items two users (which i know the name and id) have in common have bought in their entire experience in my website....
So, given the user_id = A and user_id = B how can I do a mysql query to select all the items the belong both to user A and user B?
note: I wrote a similar question but was about three tables not four. And i'm learnign a lot doing these progressive questions thanks!!!
UPDATE: my bad wrote a wrong table name, now is correct
Ill answer in pseudo code hope you understand,basicly idea is create a set of user A items and join it by item_id with set of user B items.
Obviously to generate user A and user B items you need same query with different where clause.
Select A.item_id from
(select user A items) as A
join (select user B items ) as B
on A.item_id=B.item_id
I hope you can create select user X items query
The first issue is getting all of the items a user has ever bought. This is quite easy using item_to_list:
SELECT item_id FROM item_to_list WHERE user_id = A;
However, keeping user_id inside both item_to_list and list_tb leads to lots of data duplication. (Google relational database normalisation for fun stuff on this). So I would remove the user_id field from item_to_list and rely on list_tb to store this information.
The query then becomes:
SELECT DISTINCT item_id
FROM item_to_list AS itl, list_tb AS ltb
WHERE ltb.user_id = A
AND ltb.list_id = itl.list_id;
This is assuming that your item_to_list.item_to_user_id is the same as the item_tb.list_tb
At this point you can generate a table containing a list of all of the items ever bought by a user. Now the problem becomes generating a table for user A and a table for user B and then comparing the results.
SELECT itl.item_id
FROM item_to_list AS aitl, list_tb AS altb
WHERE altb.user_id = A
AND altb.list_id = aitl.list_id;
AND aitl.item_id IN
SELECT DISTINCT item_id
FROM item_to_list AS bitl, list_tb AS bltb
WHERE bltb.user_id = B
AND bltb.list_id = bitl.list_id;
Note: This is thouroughly untested :) and there may well be improvements to be made with regards to efficiency.
EDIT: Completed answer