Query multiple rows that leads to one row in other table - mysql

I'm a noob at making mySQL queries so I couldn't get my work done. I hope you guys know the answer to my question.
I want to make options to my products. Like if you have a black t-shirt, with a tanktop model and diamonds on it. You must have the black t-shirt tanktop model and diamonds row. I want to make it like this:
table: product_option
--------------------------------
product_option_id name product_combination_id
1 Black 1
2 Diamond 1
3 Tanktop 1
4 Option 2
5 Option 2
table: product_combination
--------------------------------
product_combination_id name
1 Black tanktop with diamonds
So my question is. Is it possible to query the product_options and get an product_combination row out of it?
I hope you guys know the answer to my question! Thank you for your time :)
EDIT:
I think my question was too general and I want to ask it more specific.
Let's say. I have a shop with clothes. I have a product (let's say an T-shirt). And there are a couple of options to choose from.
Like this:
Color:
- Black
- Red
- Orange
Size
- Large
- Xtra Large
- Medium
- Small
Accessoire:
- Diamonds
- Printed
- Swarovski
Let's say I want to buy the Black / Xtra Large T-shirt with Diamonds on it. Then the product_combination must be Black/Large/Diamonds Row. I think I need an Foreign table with a Many to Many relation. Like product_combination_option table with the columns:
product_combination_option
- product_combination_option_id
- product_combination_id
- product_option_id
But then again. How can I query when someone chooses Black / Xtra Large with Diamonds and find which product_combination it is.
I hope I'm a bit clearer now. Sorry that I updated my question so late! I appreciate all your answers very much!

I think what you are looking for is joining your tables, so that you can pick up a combination based on the product you have.
So, for that, a query can be
Select *
from product_option inner join product_combination
using(product_combination_id);
This joins the 2 tables. so you can replace the * with the list of attributes you want to display/fetch.

If you mean you want to pass a list of options to the query and get a list of matching product_combination entries, then here's one way:
SELECT *
FROM product_combination
WHERE product_combination_id IN (
SELECT product_combination
FROM product_option
WHERE name IN ('option1', 'option2', 'option3')
GROUP BY product_combination
HAVING COUNT(*) = 3
);
The subquery returns a set of product_combination values that have all three options requested. The COUNT(*) = 3 condition assumes that a single product_combination value cannot have duplicate name values associated with it. (Which is only natural, but in case your table doesn't have the corresponding restriction, you could replace COUNT(*) with COUNT(DISTINCT name) to make sure a group being returned contains all three options specified and not just three rows of which some contain identical options.)
Of course, if the number of options queried isn't fixed, you'll need to build the query dynamically because of the IN predicate, because it is not parametrisable (in terms of the number of items). However, you could try using a temporary rowset instead of a hardcoded list. The table would be populated before running the query in question, which in this case would be modified to this effect:
SELECT *
FROM product_combination
WHERE product_combination_id IN (
SELECT product_combination
FROM product_option
WHERE name IN (SELECT option_name FROM requested_options)
GROUP BY product_combination
HAVING COUNT(*) = (SELECT COUNT(*) FROM requested_options)
);
In the above query, requested_options is the name of the temporary storage (possibly a temporary table, but I'm not sure if MySQL allows you to access one that was created and and populated beforehand in a different query), and option_name is its column containing the options being requested.

Related

How to select comma-separated values from a field in one table joined to another table with a specific where condition?

I'm working on a mysql database select and cannot find a solution for this tricky problem.
There's one table "words" with id and names of objects (in this case possible objects in a picture).
words
ID object
house
tree
car
…
In the other table "pictures" all the information to a picture is saved. Besides to information to resolution, etc. there are especially informations on the objects in the picture. They are saved in the column objects by the ids from the table words like 1,5,122,345, etc.
Also the table pictures has a column "location", where the id of the place is written, where I took the picture.
pictures
location objectsinpicture ...
1 - 1,2,3,4
2 - 1,5,122,34
1 - 50,122,345
1 - 91,35,122,345
2 - 1,14,32
1 - 1,5,122,345
To tag new pictures of a particular place I want to become suggestions of already saved information. So I can create buttons in php to update the database instead of using a dropdown with multiple select.
What I have tried so far is the following:
SELECT words.id, words.object
FROM words, pictures
WHERE location = 2 AND FIND_IN_SET(words.id, pictures.objectsinpicture)
GROUP BY words.id
ORDER BY words.id
This nearly shows the expected values. But some information is missing. It doesn't show all the possible objects and I cannot find any reason for this.
What I want is for example all ids fo location 2 joined to the table words and to group double entries of objectsinpicture:
1,5,122,34
1,14,32
1,5,14,32,34,122
house
...
...
...
...
...
Maybe I need to use group_concat with comma separator. But this doesn't work, either. The problem seems to be where condition with the location.
I hope that anyone has an idea of solving this request.
Thanks in advance for any support!!!
This is a classic problem of denormalization causing problems.
What you need to do is store each object/picture association separately, in another table:
create table objectsinpicture (
picture_id int,
object_id int,
primary key (picture_id, object_id)
);
Instead of storing a comma-separated list, you would store one association per row in this table. It will grow to a large number of rows of course, but each row is just a pair of id's so the total size won't be too great.
Then you can query:
SELECT w.id, w.object
FROM pictures AS p
JOIN objectsinpicture AS o ON o.picture_id = p.id
JOIN words AS w ON o.object_id = w.id
WHERE p.location = 2;

MySQL finding all elements that have the same value in column A but different values in cloumn B

I'm fairly new to SQL and have a question regarding a query.
I have a database with various pictures attached to a product. All these pictures have a prediction. The structure is like this:
product_ id picture_id prediction
1------------pic1.jpg----------type a
1------------pic2.jpg----------type b
1------------pic3.jpg----------type b
2------------pic4.jpg----------type a
2------------pic5.jpg----------type a
2------------pic6.jpg----------type a
3------------pic7.jpg----------type c
...
... so on.
Each pictures is predicted individually and because of that some of the products have contradictory predictions (meaning that on the same products some pictures are predicted type a while others are predcited type b).
I want to filter out all of these products with a query. In other words: I need all product_ids where the predictions for the pictures linked to it are not all the same. In our example I want it only to show me product 1.
I tried some stuff with GROUP BY, but have not yet gotten anywhere near the result that I want.
Thanks for helping,
Cheers
Use COUNT(DISTINCT prediction) to get the number of different predictions. It will be more than 1 for the products with different predictions.
SELECT product_id
FROM yourTable
GROUP BY product_id
HAVING COUNT(DISTINCT prediction) > 1

SQL Joins - Why does this simple join work, despite the syntax making no sense?

I've read numerous tutorials and graphical representations of MySQL joins, and they still don't make sense to me.
I'm trying to type my own now, and they are working, but I just don't see how they're working.
Take this set of tables
images squares
---------------------------- ----------------------------------
image_id | name | square_id square_id | latitude | longitude
---------------------------- ----------------------------------
1 someImg 14 1 42.333 24.232
2 newImg 3 2 38.322 49.2320
3 blandImg 76 3 11.2345 99.4323
... ...
n n
This is a one to many relationship - one square can have many images, but an image can only have one square.
Now I run this simple join, but I'm not understanding the syntax of it at all...
SELECT images.image_id
FROM squares
LEFT JOIN images ON images.square_id=squares.square_id
WHERE images.square_id=711464;
Now, this actually works, which amazes me. It brings up a list of images within the square range.
But I'm having a hard time understanding the ON syntax.
What does ON do exactly?
Does it show how the two tables are related?
Mainly however, SELECT images.image_id FROM squares, makes the least sense.
How can I select a field in one table but FROM another?
Let's start with the FROM clause, which in it's entirety is:
FROM squares LEFT JOIN images ON images.square_id=squares.square_id
(it's not just FROM squares).
This defines the source of your data. You specify both tables, squares and images so they are both sources for the data that the query will work on.
Next, you use the on syntax to explain how this tables are related to one another. images.square_id=squares.square_id means: consider a row in the images table related to a row in the squares table if and only if the value of the field square_id of the images row is equal to the value of the field square_id of the squares table. At this moment, each row of the result is a combination of a row from the images table and a row from the squares table (I'll ignore the LEFT JOIN at the moment).
Next, you have the WHERE clause
WHERE images.square_id=711464
This means, from the rows that are in result set, just get those where the value of the square_id field, in that part of the result row that came from the images table, is exactly 711464.
And last comes the SELECT part.
SELECT images.image_id
This means, from the rows that are in the result set (a combination of a square row and a images row), take just the field image_id that is from the images table.
You should read the query as such:
SELECT images.image_id FROM
squares LEFT JOIN images
ON images.square_id=squares.square_id
WHERE
images.square_id=711464
So you first join the squares table with the images table, combining entries in images which have the same square_id as in the squares table. So, the ON syntax is actually specifying the condition on which the two tables should be joined.
Then, you do a filter using WHERE, which will take the entries with square_id=711464
Note that by the time you do the SELECT, you already joined the two tables, which will have the combined fields:
images
--------------------------------------------------
square_id | latitude | longitude | image_id | name
--------------------------------------------------
So, you can select the square_id from the resulting table.
It is more like :
SELECT images.image_id FROM (squares LEFT JOIN images ON images.square_id=squares.square_id WHERE images.square_id=711464)
So you don't select a field from another table - it is more like you create a new temporary table from the statement in brackets (actually having columns from multiple tables) and then perform SELECT on this table.
And yes, ON defines how the tables are related (for instance with foreign key)
SELECT [COLUMNS] --First Line Of Code - say it as 1
FROM --Second Line Of Code -- say it as 2
[Table1] Join [table2] On [Criteria] --say it as 3
Where [Some More Criteria] --Say it as 4
Whenever a
Select Column From
is done it gets the data from 3 which is collection of multiple table or single table.
Once the data is loaded it Executes the where criteria for filtering the data.
After data filtration Select statement will be Executed.
In your case:
Left Join will execute and generate table with 6 columns. based on Join Criteria. Than Where criteria will be executed to filter the data.
Select statement execution will takes place only after that.
Regarding using the Table Name as prefix is to avoid the conflict in Column Name.
P.S : This is for your understanding, actually the data load doesn't happen. To understand exactly how queries are executed you need to understand DB Engine.
As Of Now,Write query and leave the DB Engine for planning.
With Experience Comes The Knowledge.
Happy Coding

How to convert list field into many-to-many table in MySQL

I have inherited a database in which a person table has a field called authorised_areas. The front end allows the user to choose multiple entries from a pick list (populated with values from the description field of the area table) and then sets the value of authorised_areas to a comma-delimited list. I am migrating this to a MySQL database and while I'm at it, I would like to improve the database integrity by removing the authorised_areas field from the person table and create a many-to-many table person_area which would just hold pairs of person-area keys. There are several hundred person records, so I would like to find a way to do this efficiently using a few MySQL statements, rather than individual insert or update statements.
Just to clarify, the current structure is something like:
person
id name authorised_areas
1 Joe room12, room153, 2nd floor office
2 Anna room12, room17
area
id description
1 room12
2 room17
3 room153
4 2nd floor office
...but what I would like is:
person
id name
1 Joe
2 Anna
area
id description
1 room12
2 room17
3 room153
4 2nd floor office
person_area
person_id area_id
1 1
1 3
1 4
2 1
2 2
There is no reference to the area id in the person table (and some text values in the lists are not exactly the same as the description in the area table), so this would need to be done by text or pattern matching. Would I be better off just writing some php code to split the strings, find the matches and insert the appropriate values into the many-to-many table?
I'd be surprised if I were the first person to have to do this, but google search didn't turn up anything useful (perhaps I didn't use the appropriate search terms?) If anyone could offer some suggestions of a way to do this efficiently, I would very much appreciate it.
While it is possible to do this I would suggest that as a one off job it would probably be quicker to knock up a php (or your favorite scripting language) script to do it with multiple inserts.
If you must do it in a single statement then have a table of integers (0 to 9, cross join against itself to get as big a range as you need) and join this against your original table, using string functions to get the Xth comma and from that each of the values for each row.
Possible, and I have done it but mainly to show that having a delimited field is not a good idea. It would likely be FAR quicker to knock up a script with multiple inserts.
You could base an insert on something like this SELECT (although this also comes up with a blank line for each person as well as the relevant ones, and will only cope with up to 1000 authorised areas per person)
SELECT z.id, z.name, x.an_authorised_area
FROM person z
LEFT OUTER JOIN (
SELECT DISTINCT a.id, SUBSTRING_INDEX( SUBSTRING_INDEX( authorised_areas, ",", b.ournumbers ) , ",", -1 ) AS an_authorised_area
FROM person a, (
SELECT hundreds.i *100 + tens.i *10 + units.i AS ournumbers
FROM integers AS hundreds
CROSS JOIN integers AS tens
CROSS JOIN integers AS units
)b
)x ON z.id = x.id

Selecting multiple rows based on specific categories (mysql)

I don't think this is a duplicate posting because I've looked around and this seems a bit more specific than whats already been asked (but I could be wrong).
I have 4 tables and one of them is just a lookup table
SELECT exercises.id as exid, name, sets, reps, type, movement, categories.id
FROM exercises
INNER JOIN exercisecategory ON exercises.id = exerciseid
INNER JOIN categories ON categoryid = categories.id
INNER JOIN workoutcategory ON workoutid = workoutcategory.id
WHERE (workoutcategory.id = '$workouttypeid')
AND rand_id > UNIX_TIMESTAMP()
ORDER BY rand_id ASC LIMIT 6;
exercises table contains a list of exercise names, sets, reps, and an id
categories table contains an id, musclegroup, and type of movement
workoutcategory table contains an id, and a more specific motion (ie: upper body push, or upper body pull)
exercisecategory table is the lookup table that contains (and matches the id's) for exerciseid, categoryid, and workoutid
I've also added a column to the exercises table that generates a random number upon entering the row in the database. This number is then updated only for the specified category when it is called, and then sorted and displays the ascending order of the top 6 listings. This generates a nice random entry for me. (Found that solution elsewhere here on SO).
This works fine for generating 6 random exercises from a specific top level category. But I'd like to drill down further. Here's an example...
select all rows inside categoryid 4
then still within the category 4 results, find all that have movementid 2, and then find one entry with a typeid 1, then another for typeid 2, etc
TLDR; Basically there's a few levels of categories and I'm looking to select a few from here and a few from there and they're all within this top level. I'm thinking this could all be executed within more than one query but im not sure how... in the end I'm looking to end with one array of the randomized entries.
Sorry for the long read, its the best explanation I've got.
Just realized I never came back to this posting...
I ended up using several mysql queries within a switch based on what is needed during the request. Worked out perfectly.