SQL query select from multiple tables problem [duplicate] - mysql

This question already has answers here:
Many-to-many relationships examples
(5 answers)
Closed 1 year ago.
I have a mySQL database containing where Schools located in different countries provide training (the product) in different cars, with different objectives.
SCHOOLS
id| schoolname |
----------------------------------
1 | Pete’s Driving school |
2 | Karen’s Driving school |
3 | John’s Driving school |
4 | Donald’s Driving school |
CARS
id| carbrand |
----------------------------------
1 | Buick |
2 | Mercedes |
3 | Tesla |
4 | Audi |
PROVIDES (PROVIDES THIS TRAINING)
id| name |
----------------------------------
1 | Get License |
2 | Practise driving |
3 | Maneuvering |
4 | Winter training |
LOCATIONS
id| name |
----------------------------------
1 | USA |
2 | UK |
3 | France |
4 | Japan |
I also have these tables telling me which schools have which cars, which location, and provide which training:
SCHOOL_OWNS
id| schoolid | carsid
----------------------------------
1 | 1 | 2
2 | 1 | 1
3 | 2 | 1
4 | 3 | 2
SCHOOL_PROVIDES
id| schoolid | providesid
----------------------------------
1 | 1 | 2
2 | 1 | 3
3 | 2 | 1
4 | 3 | 2
SCHOOL_LOCATIONS
id| schoolid | locationsid
----------------------------------
1 | 1 | 2
2 | 2 | 4
3 | 2 | 1
4 | 3 | 2
My products which I'm trying to select and output..
PRODUCT
id| productname | schoolid | carid | locationid | price
----------------------------------
1 | Product1 | 2 | 1 | 4 | 400 USD
2 | Product2 | 3 | 1 | 2 | 300 USD
3 | Product3 | 1 | 2 | 1 | 200 USD
4 | Product4 | 2 | 2 | 1 | 100 USD
My question is now how to write a JOIN query to get what I'm looking for. This is doing my head in and not even sure where to start or if the way I have done it is a recommended way of setting it up?
I’m trying to create a SQL query that lets me select and sort depending on three criteria, car brand, provides and location.
I have on the top of the page three dropdown menus "CARS", "PROVIDES SERVICE" and "LOCATION".
What SQL Query could match these two scenarios?! Thanks I'm a bit lost..
1. If I want to display all products that fulfill all
these three criteria (Buick, Maneuvering, Japan)
cars=1&provides=3&location=4
Output (only one product meet this criteria):
Product1 | Karen’s Driving school | 400 USD
-------------------
2. And if I only want display all products that provide ‘practise driving’ ?cars=&provides=2&location= ,
Then all products should show that have a company that provides “practice driving” ..
Output (only one two products meet this criteria):
Product1 | Karen’s Driving school | 400 USD
Product3 | John’s Driving school | 200 USD

it looks like you can't make those joins since you do not have foreign keys in your tables.
as an example.. linking cars id to a provides id will not work, so it can't reach that table an easy way... you will need a foreign key or make a sub table to make it easier for yourself!

Related

Does Cross Join not work between two different tables with same column name?

As written on the title, does CROSS JOIN not work for different tables with the same column name?
For example,
I have one table named Fruits:
| name | price |
| apple | 1 |
| banana | 2 |
and another table named Snacks:
| name | price |
| chips | 3 |
| cookies | 4 |
Then does
SELECT Fruits.price, Snacks.price FROM Fruits CROSS JOIN Snacks
does not work properly?
I am working on a same issue, but the result shows like:
| price | price |
| 3 | 3 |
| 4 | 4 |
| 3 | 3 |
| 4 | 4 |
But what I expect is:
| price | price |
| 1 | 3 |
| 1 | 4 |
| 2 | 3 |
| 2 | 4 |
As I mentioned in the comment, it is not possible. Either your tables values are different or your query.
Check this dbfiddle showing the result value same as your expected values.
In MySQL CROSS JOIN works as expected:
price price
------ -----
1 3
2 3
1 4
2 4
See running example at DB Fiddle.

SQL - Aggregate all EXCEPT group

Consider the following sample table from a soccer tournament (let's call this table matches)
+----------+---------+--------------+
| match_id | club_id | goals_scored |
+----------+---------+--------------+
| 1 | 1 | 1 |
| 1 | 2 | 0 |
| 2 | 1 | 1 |
| 2 | 3 | 1 |
| 3 | 1 | 0 |
| 3 | 4 | 2 |
| 4 | 2 | 2 |
| 4 | 3 | 4 |
| 5 | 2 | 4 |
| 5 | 4 | 0 |
| 6 | 3 | 1 |
| 6 | 4 | 1 |
+----------+---------+--------------+
The resulting table we want should give us each club's total goals scored AND goals conceded:
+---------+--------------+----------------+
| club_id | goals_scored | goals_conceded |
+---------+--------------+----------------+
| 1 | 2 | 4 |
| 2 | 6 | 4 |
| 3 | 6 | 4 |
| 4 | 3 | 5 |
+---------+--------------+----------------+
Getting goals scored is straight forward enough...
SELECT SUM(goals_scored),
club_id
FROM matches
GROUP BY club_id
but I am absolutely flummoxed as to how to get it for each team's opponents.
I could, of course, construct a pretty complex array of subqueries to get there. If this were application-side work I'd likely just stuff it in a loop and iterate over each club to get there, but my use case requires a SQL answer if possible. Any thoughts?
edit: also if anyone has any better ideas on how to title this question, I'm all ears - I'm not really sure exactly how to describe this problem in the first place.
We can use a self-join approach here:
SELECT
m1.club_id,
SUM(m1.goals_scored) AS goals_scored,
SUM(m2.goals_scored) AS goals_conceded
FROM matches m1
INNER JOIN matches m2
ON m2.match_id = m1.match_id AND
m2.club_id <> m1.club_id
GROUP BY
m1.club_id
ORDER BY
m1.club_id;
This approach brings the goals conceded by each club to the other club, for each match, into a single row. We then just aggregate by club to get the two sums.

Normalisation of product/protocol review system

I'm working on a review system, where reviews for products are shown based on the outcome of a questionnaire.
Example:
What food do you like (Italian, French or fusion)
Which vegetables do you like (spinach, tomato or broccoli)
How much money would you like to spend on dinner ($0-$10, $11-$20 or $21-$30)
If someone selects Italian, tomato, $0-$10, then the user would see (for example) 20 types of pizza's, with reviews from other users shown.
But we only want to show products that have been reviewed for the exact same outcome of the questionnaire (we call this the protocol).
Table: questions
-----------------------------------
| id | question |
-----------------------------------
| 1 | What food do you like |
-----------------------------------
| 2 | Which vegetables do you... |
-----------------------------------
Table: possible_answers
-----------------------------------
| id | question_id | answer |
-----------------------------------
| 1 | 1 | Italian |
-----------------------------------
| 2 | 1 | French |
-----------------------------------
Table: products
---------------------
| id | product |
---------------------
| 1 | Pizza Salami |
---------------------
| 2 | Pizza cheese |
---------------------
From a database perspective (we're using mySQL), I'm wondering how to store the protocol attached to each review
[OPTION 1]
Table: reviews
---------------------------------------------------------------------------
| id | product_id | answer_q1_id | answer_q2_id | answer_q3_id | rating |
---------------------------------------------------------------------------
| 1 | 2 | 3 | 57 | 166 | 4 |
---------------------------------------------------------------------------
| 2 | 25 | 3 | 57 | 166 | 5 |
---------------------------------------------------------------------------
[/OPTION 1]
[OPTION 2]
Table: reviews
-------------------------------
| id | product_id | rating |
-------------------------------
| 1 | 2 | 4 |
-------------------------------
| 2 | 25 | 5 |
-------------------------------
Table: protocol
-----------------------------------------------
| id | review_id | question_id | answer_id |
-----------------------------------------------
| 1 | 1 | 1 | 3 |
-----------------------------------------------
| 2 | 1 | 2 | 57 |
-----------------------------------------------
| 2 | 1 | 3 | 166 |
-----------------------------------------------
[/OPTION 2]
Normally, I'd go with option 2 which just 'feels' better. But I'm not sure how one could query the protocol table to get all product reviews for a specific path in the questionnaire (protocol). For example when the user answers 'italian, spinach, 0-10', how do I find out which product reviews go with that combination of answers using option 2 (with option 1 it is obvious how to do this)?
I hope I've explained this well and I'm looking forward to reading thoughts from the community.
Greatly appreciated,
Lionel.

MySQL - Optimizing column referencing?

I'm having difficulty trying to form the actual question I have, so hopefully I can get the point across with visual aid.
What I'm wondering is whether or not my current database design is horribly flawed, slightly inefficient, or ... correct.
Q: Is there a better way for a row cell to reference a column in another table, aside from just saving a string of that column's name?
Example:
There are two tables.
table01: has 3 columns - c_id, customer, tier (tier holds the column name of a tier in table02 )
table02: has 5 columns - i_id, item, tier1, tier2, tier3
table01 +------+----------+------+
|'c_id'|'customer'|'tier'|
+------+----------+------+
| 1 | John | tier1|
| 2 | Lisa | tier2|
| 3 | Mike | tier1|
| 4 | Tom | tier3|
+------+----------+------+
table02 +------+------+-------+-------+-------+
|'i_id'|'item'|'tier1'|'tier2'|'tier3'|
+------+------+-------+-------+-------+
| 1 | apple| $1.99 | $2.99 | $3.99 |
| 2 | chalk| $2.99 | $3.99 | $4.99 |
| 3 | pens | $3.99 | $4.99 | $5.99 |
| 4 | shirt| $4.99 | $5.99 | $6.99 |
+------+------+-------+-------+-------+
Result:
John +------+-------+
| apple| $1.99 |
| chalk| $2.99 |
| pens | $3.99 |
| shirt| $4.99 |
+------+-------+
Selecting John's row would yield tier1, which is then used to query for table02.tier1, and grab that column's contents. (In this discounted prices for tier1 customers). The tier1 items would then be displayed with their correct prices.
Is there a more efficient way to reference an outside table's column name, like... in the style of foreign keys? Where if the column name changes, then that information waterfalls to other linked data cells? Is my approach correct, or should I restructure how I'm doing things?
It isn't completely clear how the c_id and i_id columns are supposed to be used, but a more conventional design would be to use a design like this:
table01 +------+----------+------+
|'c_id'|'customer'|'tier'|
+------+----------+------+
| 1 | John | 1 |
| 2 | Lisa | 2 |
| 3 | Mike | 1 |
| 4 | Tom | 3 |
+------+----------+------+
table02 +------+------+-------+
|'i_id'|'tier'|'cost' |
+------+------+-------+
| 1 | 1 | $1.99 |
| 2 | 1 | $2.99 |
| 3 | 1 | $3.99 |
| 4 | 1 | $4.99 |
| 1 | 2 | $2.99 |
| 2 | 2 | $3.99 |
| 3 | 2 | $4.99 |
| 4 | 2 | $5.99 |
| 1 | 3 | $3.99 |
| 2 | 3 | $4.99 |
| 3 | 3 | $5.99 |
| 4 | 3 | $6.99 |
+------+------+-------+
I edited the example to better exemplify my thoughts. Which really doesn't change your answer much. So it'd be better to consolidate the tier columns into one column and just repeat the item id (i_id) data several times? My reasoning behind breaking the tier/cost structure into columns was to cut down on redundancy. Would that approach require me to make a new table to index the tiers for foreign keys?
I understand what you're doing now. Somewhere along the line, you might have a 'Sales' table which records a c_id, and i_id, a quantity, a date and other such information (if each sale consists of one item; otherwise, you'd have an 'Orders' table and an 'OrderItems', and the c_id would be associated with the orders table and the i_id would be associated with order items, and there'd be an order number to connect the two tables).
If you add your item desciption to the revised table02 above, you would be violating 3NF. You should have a table such as 'Products' with the i_id and item columns. This would give names to item numbers. The table02 (maybe 'TieredItemCosts') table I proposed would remain as it is; the primary key is the combination of (i_id, tier).

Mysql, storing multiple value in single column from another table

Bear with me, im really bad at explaining thing and i dont even know an appropriate title for this problem
Ok guys i have this problem
I already have one table name meal
+------+--------+-----------+---------+
| id | name | serving | price |
+------+--------+-----------+---------+
| 1 | soup1 | 2 person | 12.50 |
+------+--------+-----------+---------+
| 2 | soup2 | 2 person | 15.50 |
+------+--------+-----------+---------+
| 3 | soup3 | 2 person | 23.00 |
+------+--------+-----------+---------+
| 4 | drink1 | 2 person | 4.50 |
+------+--------+-----------+---------+
| 5 | drink2 | 2 person | 3.50 |
+------+--------+-----------+---------+
| 6 | drink3 | 2 person | 5.50 |
+------+--------+-----------+---------+
| 7 | frui1 | 2 person | 3.00 |
+------+--------+-----------+---------+
| 8 | fruit2 | 2 person | 3.50 |
+------+--------+-----------+---------+
| 9 | fruit3 | 2 person | 4.50 |
+------+--------+-----------+---------+
Ok now i want to allow admin to create a combo meal from this meal table
So that mean, a combo meal can have unlimited number amout of meal
Currently im puzzle how to store/link combo meal to the meal
I donw want to store something lke below
+------+--------------+-----------+-----------+
| id | combo_name | serving | meal_id |
+------+--------------+-----------+-----------+
| 1 | combo1 | 2 person | 1,4,7,9 |
+------+--------------+-----------+-----------+
| 2 | combo2 | 2 person | 2,5,8 |
+------+--------------+-----------+-----------+
| 4 | combo3 | 2 person | 3,5,6,9 |
+------+--------------+-----------+-----------+
Look at the meal_id column, i dont think that is a good way to store a data
Create a many-to-many link table:
combo_id meal_id
1 1
1 4
1 7
1 9
2 2
2 5
2 8
3 3
3 5
3 6
3 9
To select all meals for a given combo:
SELECT m.*
FROM combo_meal cm
JOIN meal m
ON m.id = cm.meal_id
WHERE cm.combo_id = 1
No. It's definitely not a good way to store data. You will be better with a combo_header table and a combo_details table.
combo_header will be something like:
+------+--------------+-----------+
| id | combo_name | serving |
+------+--------------+-----------+
| 1 | combo1 | 2 person |
+------+--------------+-----------+
| 2 | combo2 | 2 person |
+------+--------------+-----------+
| 4 | combo3 | 2 person |
+------+--------------+-----------+
And then, combo_details will be something like:
+------+-----------+
| id | meal_id |
+------+-----------+
| 1 | 1 |
+------+-----------+
| 1 | 4 |
+------+-----------+
| 1 | 7 |
+------+-----------+
| 1 | 9 |
+------+-----------+
... / you get the idea!
By the way, by using multiple values in a single column you are violating first normal form of relational databases.
The way I'm proposing will let you answer queries like get all name of the meals of combo1 very easy to resolve.
This is called a many-to-many relationship between meals and combo. A meal can be listed in multiple combos and a combos can contain multiple meals. You will need a link table (instead of the combo.meal_id field) that contains all possible meal-combo pairs.
In the end, you will have three tables:
meal (meal_id, serving, name)
combo (combo_id, serving, name)
meal_combo (autoid, meal_id, combo_id)
meal_combo.autoid is not strictly needed, it's just a general recommendation.
To list a combo with all it's meals in it:
SELECT meal.id, meal.name FROM comboINNER JOIN meal_combo ON meal_combo.combo_id = combo.id INNER JOIN meal ON meal.id = meal_combo.meal_id WHERE combo.id = 132
Google for 'many-to-many relationship' or 'database link table' for details.