Let's say we have 2 db tables.
First table "laptops"
id | name
1 apple
2 sony
...
and second table "colors"
id | color
1 white
2 black
2 red
2 blue
...
If I want to get some html table like
Laptop | Available colors
Apple 1 (white)
Sony 3 (red, blue, black)
...
I need to create "while" and query every time for every laptop. It will load server if there are more than 10 000 laptops for example. Is there any optimised way to get it work?
What you are looking for is a SQL JOIN. However you need to have a table which links both tables together.
Something like
SELECT * FROM laptops t
LEFT JOIN colors c ON t.id=c.id
e.g. if you want to Count colors you could do something like this:
SELECT t.id, t.name, COUNT(c.id) AS numberofcolors FROM laptops t
LEFT JOIN colors c ON t.id=c.id
GROUP BY t.id
If you also need to output color names you have to use GROUP_CONCAT
Related
This is my product table
and I want to get all product where product_sizes in (Xl, M)
I am trying into this code
SELECT `id`,`name`,`sell_price`,`product_sizes`,`product_colors`
FROM `view_product_listing`
WHERE `product_sizes` in ('XL', 'M')
return to me productId 15 and 16 but I want to productId 4,14,15,16
You should seriously avoid storing the sizes as CSV (comma separated) data, see below for an alternative table design. As a workaround, we can use FIND_IN_SET:
SELECT id, name, sell_price, product_sizes, product_colors
FROM view_product_listing
WHERE FIND_IN_SET('M', product_sizes) > 0 OR FIND_IN_SET('XL', product_sizes) > 0;
But note that a much better database design would be to have a separate table for products, sizes, and colors: (colors omitted)
products
id | name | sell_price |
4 | Women Maxi White Dress | 550.00 |
14 | Women Maxi Blue Dress | 700.00 |
15 | Women Fit and Flare Multicolor Dress | 750.00 |
16 | Floral Print Straight Kurta | 699.00 |
sizes
product_id | product_size
4 | XL
4 | M
14 | XL
14 | XXL
14 | L
14 | M
15 | XL
16 | M
Now we can use a straightforward join to find all products, and their metadata, which have either the medium or XL size:
SELECT
p.id,
p.name,
p.sell_price,
s.product_size
FROM products p
INNER JOIN sizes s
ON p.id = s.product_id
WHERE
s.product_size IN ('M', 'XL');
use find_in_set()
SELECT `id`,`name`,`sell_price`,`product_sizes`,`product_colors`
FROM `view_product_listing`
WHERE FIND_IN_SET(product_sizes,'XL,M')
If you are only searching for one size you could use the built-in MySQL function FIND_IN_SET()
SELECT `id`,`name`,`sell_price`,`product_sizes`,`product_colors`
FROM `view_product_listing`
WHERE FIND_IN_SET('XL', product_sizes)
However it only supports a single string (unless you add additional OR's, but that quickly becomes tedious).
The best approach would be to restructure your database so that the product sizes of items are in a seperate table with a reference to the item table and a size table.
That way you don't have to update your queries whenever you want to introduce new sizes and it will improve performance for your query.
A word of warning,
Do not attempt a LIKE clause, because search for LIKE '%XL%' will also match XXL
You can use FIND_IN_SET like this,
Version 1:
SELECT `id`,`name`,`sell_price`,`product_sizes`,`product_colors`
FROM `view_product_listing`
WHERE FIND_IN_SET('XL',product_sizes) OR FIND_IN_SET('M',product_sizes)
EDIT 1
There is one more approach to achieve this,
Version 2:
SELECT `id`,`name`,`sell_price`,`product_sizes`,`product_colors`
FROM `view_product_listing`
WHERE CONCAT(',',product_sizes,',') REGEXP ",(XL|M),"
Source link for second version.
EDIT 2
You product_sizes is having spaces after commas, which is not the behaviour find_in_set is expecting. To trim all spaces from that column,
UPDATE `table` SET `product_sizes` = REPLACE(`product_sizes`, ' ', '')
And now run any version query you want to try, it will work.
I have two tables as follows:
games
id | game_name | console_id
1 God of War 1
2 Zelda 3
3 Sonic 4
consoles
id | console_name
1 PS4
2 Xbox
3 Switch
4 Mega Drive
I've linked them via the Designer view so when I go to insert a name game (I'm doing this via the phpMyAdmin control panel) as soon as I click on "console_id" it gives me a drop down of 1 - PS4, 2 - Xbox and so on. So the games table can now read from consoles table no problem so I think I've got everything correct from that side of things.
Now I can run this code
SELECT id, game_name, console_id FROM games
and I will get the output
1 - God of war - 1
What I would like to do is something like this:
SELECT id, game_name, console_id.console_name FROM games
So instead of it saying God of war is on console ID 1, it says its on console.name PS4.
How can I do it, as I thought by linking the tables it would allow me to do it.
You need a JOIN between the tables. In this case, you want to join the consoles table to the games table by matching the id field of the former to the console_id field of the latter, like this:
SELECT g.id, g.game_name, c.console_name
FROM games g
INNER JOIN consoles c
ON c.id = g.console_id
I have three tables in a mySQL db one for users, one for colours and one for the linking of the users to the colours
Table 1 users
==============
ID | Name
--------------
1 | John
2 | Jayne
3 | Fred
Table 2 colours
==============
ID | Colour
--------------
1 | Blue
2 | Red
3 | Yellow
Table 3 link
==============
ID | Name | Colour
--------------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 3 | 2
5 | 3 | 3
As you can see, some users have more than one favourite colour (yeah, i know, how annoying).
At the moment, I can show them in a table, with their favourite colour(s) in a column.
BUT, I want to be able to filter the table results by colour.
I can do it no problem with having a filter of just one colour, BUT the problem comes along with two colours.
If I want to see which user has selected for example Blue AND Red, I get a result of zero.
How can I get this result, without creating a search which results in each row being dedicated to a colour and then in turn showing the same user twice (one for red one for blue).
I hope this makes sense
THANKS IN ADVANCE
EDIT
An example query I have used is
SELECT * FROM users, colours, link WHERE users.id = link.name AND link.colour = colours.id
Alternatively to show for specific colour
SELECT * FROM users, colours, link WHERE users.id = link.name AND link.colour = colours.id AND link.colour = 1
But for double filter which shows duplicates
SELECT * FROM users, colours, link WHERE users.id = link.name AND link.colour = colours.id AND link.colour = 1 OR link.colour = 2
If that looks right here is the code:
SELECT Name FROM users
WHERE ID IN (SELECT DISTINCT(Name) AS Name
FROM link L
WHERE 2 IN (SELECT Colour FROM link L2 WHERE L.Name = L2.Name)
AND 1 IN (SELECT Colour FROM link L2 WHERE L.Name = L2.Name))
And now let me try to explain what L and L2 are... First sorry for my English I'll do my best to make a sense for you...
We make subquery on the same table here so we need to use alias for the table. Alias we use to give temporary name table or column which will be used only for that query.
Example for alias is when we select some column from table (Price and Quantity) and let's say we want to calculate Price * quantity and SELECT that column as total (total will be the name of that column in table which we return after we execute the query). Column name total well be give alias. we crate alias like:
SELECT Price, Quantity, (Price * Quantity) AS **total**
FROM t1...
That will return table with three column Price, Quantity, Total... if we don't use this AS total the name of that column will be Price * Quantity...
So here we use L and L2 just to know which column Name is from which part of SELECT query. If we wouldn't use alias in subquery
SELECT Colour FROM link L2 WHERE L.Name = L2.Name
we would have problem because subquery which locks like this:
SELECT Colour FROM link WHERE Name = Name
Doesn't make a a lot of sense, isn't it?
So basically we temporary rename table in this query because we need to know which column from which table we compere whit other one, in other way database will have a problem what to select...
I hope this make a sense for you. If you have any further question fill free to ask I will do my best to try to explain it to you.
I hope i didn't make it more complicated than it is...
GL!
EDIT
Hi there again, i worked something and and i figured out that your question probably have better answer than the first i give you... Hope it's not too late!
SELECT u.Name
FROM users u
INNER JOIN link L
ON u.ID = L.Name
INNER JOIN link l2
ON L.Name = L2.Name
WHERE L.Colour = 2 AND L2.Colour = 1
Look SQL Fiddle for that...
I'm using php my get results from a mysql table. I want to run multiple conditional statements to return a list of unique results. let's say I have a table about houses on my street and my table looks like this:
House Number | Attribute | Value
-------------------------------
23 | Colour | White
23 | Stories | 2
24 | Stories | 1
25 | Colour | Blue
Notice house number 23 appears twice How would I word a mysql query to return all houses that are white AND have two stories? in this case, it would return just one result - 23.
I hear what you're saying - why don't i just make 'colour' and 'stories' the column names. well, the reason is because in my example, a house can have two different colours: two different values for the same attribute name. A house could have two rows, one where attribute is colour and value is white, and another where attribute is also colour but the value is purple. As long as a house has a row with colour:white AND a row with stories:2 it will return positive in the query and get included in the result
Now, once solution would be to run two different queries: one query that matches white houses and returns an array, and a second query that matches houses with two stories and returns an array, then I can use php to compare the two arrays and see what entries appear in both arrays, pull them out and put them into a final array. But this involves calling two mysql queries. Is there a way of combining the queries on the mysql end?
You want a self-join:
SELECT
A.`House Number` AS House
FROM
Houses AS A
INNER JOIN Houses AS B ON A.`House Number`=B.`House Number`
WHERE
A.Attribute='Colour' AND A.Value='White'
AND B.Attribute='Stories' AND B.Value='2'
You can nest your SELECT statements like this:
SELECT DISTINCT (`House_Number`) AS `House_Number`
FROM `table`
WHERE `House_Number`
IN (
SELECT DISTINCT (`House_Number`) AS `House_Number`
FROM `table`
WHERE `Attribute` = 'Colour'
AND `Value` = 'White'
)
AND `Attribute` = 'Stories'
AND `Value` = '2';
Edit:
Not quite as pretty as using an INNER JOIN, but still effective.
To build upon the INNER JOIN method #Eugen posted while I was typing up my original response, you may consider including DISTINCT, like this:
SELECT DISTINCT(A.`House_Number`) AS `House_Number`
FROM `table` AS A
INNER JOIN `table` AS B ON A.`House_Number` = B.`House_Number`
WHERE A.Attribute = 'Colour'
AND A.Value = 'White'
AND B.Attribute = 'Stories'
AND B.Value = '2'
The reason being that in case the same attribute were to be recorded twice, say like this:
House Number | Attribute | Value
-------------------------------
23 | Colour | White
23 | Colour | White
23 | Stories | 2
24 | Stories | 1
25 | Colour | Blue
...then you would wind up with "23" being returned twice, unless you used DISTINCT
Try this
select id from table
where Attribute='Colour' and Value='White'
and id in (select id from table where Attribute='Stories' and Value='2')
I have created a database and website that will be used by football managers to select their team etc. Once a match has been completed events will be stored in the match_players table. Such events are Goal, Yellow Card, Red Card etc. I have no problem getting this information into php from SQL db.
I need to add up how many times a Goal appears (a '1' is placed in the SQL table) and for what team so that a final score can be displayed. So, for example, if Team A has 1 goal and Team B has 2 then I need to display that. I am trying to count the amount of times that a Goal is registered in the table. Any help will be greatly appreciated.
You can use MYSQL SUM
select SUM(Goal) from match_players where Team="A"
Or you can get the same for all teams by
select Team,SUM(Goal) from match_players group by Team
Why don't you demand this sum to SQL directly?
SELECT SUM(goals)
FROM match_table
WHERE team = 'Barcellona'
This should be much faster also than elaborate all data at "php-level"
If you want this detail for all teams
SELECT team,SUM(goals)
FROM match_table
GROUP BY team
Well if you store a 1 each time a goal is scored, your table looks like this:
TeamID goal
1 1
2 1
1 1
3 1
2 1
2 1
1 1
So you just want a count of how many times a team appears in that table:
select TeamID, count(*) from table group by TeamID
Will give you
TeamID | count(*)
1 | 3
2 | 3
3 | 1