I have two tables in my MySQL database:
table_bookings:
id - bookings
1 - 1
2 - 1,2,3
3 - 2,3
table_services:
id - name
1 - Facial
2 - Corporal
3 - Others
I need to make a query to get the following result:
id - services_id - services_name
1 - 1 - Facial
2 - 1,2,3 - Facial, Corporal, Others
3 - 2,3 - Corporal, Others
First Change your table layout to something like this:
table_bookings:
id | booking
1 | 1
2 | 1
2 | 2
2 | 3
3 | 2
3 | 2
After that you can join this table by booking-id to the Translation:
SELECT * FROM table_bookings AS a JOIN table_services AS b ON a.booking = b.id
If you Play around with GROUP_CONCAT after that you should get your desired result.
It looks like you need to join table table_bookings to table table_services to combine information from both tables in the result.
To join the two tables, you need to join them on a matching column. In other words, there needs to be a column in both tables which essentially represents the same thing -- then you can join using this column.
It looks like column bookings in table_bookings corresponds to id in table_services so you should join on these columns.
Consider normalize data. This can be done with these queries from existing data:
CREATE TABLE booking_services AS
SELECT DISTINCT b.id AS booking_id, s.id AS service_id
FROM table_bookings b
INNER JOIN table_services s ON FIND_IN_SET(s.id, b.bookings) > 0;
ALTER TABLE booking_services
ADD PRIMARY KEY (booking_id, service_id);
After normalization your query can be this:
SELECT
bs.booking_id,
GROUP_CONCAT(bs.service_id ORDER BY bs.service_id) AS services_id,
GROUP_CONCAT(s.name ORDER BY bs.service_id SEPARATOR ', ') AS services_name
FROM
booking_services bs
INNER JOIN
table_services s ON s.id = bs.service_id
GROUP BY bs.booking_id
Yes, you can write query on non normalized data:
SELECT
b.id,
b.bookings AS services_id,
GROUP_CONCAT(s.name ORDER BY s.id SEPARATOR ', ') AS services_name
FROM
table_bookings b
INNER JOIN
table_services s ON FIND_IN_SET(s.id, b.bookings) > 0
GROUP BY b.id, b.bookings
But on large data sets query on normalized data performs faster - see execution plans (See EXPLAIN syntax).
Test both queries on SQL Fiddle
Documentation:
Database normalization
CREATE TABLE ... SELECT Syntax
ALTER TABLE Syntax
FIND_IN_SET(str,strlist)
GROUP_CONCAT(expr)
Related
PEOPLE PEOPLE_FAVS
id user_id fav_id
------ ------- ----------
1 1 1
2 1 2
3 1 5
4 2 1
5 2 2
6
I have two tables PEOPLE and PEOPLE_FAVS, I am trying to get all PEOPLE which have not favorited number '5' so it should return
PEOPLE
id
------
2
3
4
5
6
I'm trying with this query:
SELECT `people`.`id`
FROM `people`
LEFT OUTER JOIN `people_favs` ON (`people_favs`.`user_id` = `people`.`id`)
WHERE (`people_favs`.`fav_id` != 5)
GROUP BY `people`.`id`
Here is a SQL Fiddle: http://sqlfiddle.com/#!2/4102b8/3
SELECT p.*
FROM people p
LEFT
JOIN people_favs pf
ON pf.user_id = p.id
AND pf.fav_id = 5
WHERE pf.fav_id IS NULL
http://sqlfiddle.com/#!2/665b6/1
You don't actually need to use an outer join. Outer joins are often used when you want to see ALL rows from one table, regardless of their condition with another. While it would work in this case (as seen by Strawberry's example), you can use the NOT EXISTS operator to check for ids that do not have 5 as a favorite.
As far as I am aware, there is little to no performance difference, but this query is a little shorter. I also feel it is a little more logical, because you aren't really joining information. That's just a personal opinion/thought though.
Try this:
SELECT id
FROM people
WHERE NOT EXISTS(SELECT id FROM people_favs WHERE fav_id = 5 AND user_id = id);
SQLFiddle example using your data.
Did you try to simply do this:
SELECT DISTINCT `people`.`id`
FROM `people`
JOIN `people_favs` ON (`people_favs`.`user_id` = `people`.`id`)
WHERE (`people_favs`.`fav_id` <> 5)
GROUP BY `people`.`id`
I have a table that contains as comma separated values in three fields the primary keys of three different tables, for example:
Table A (Main table):
id title companyid countryid regulatorid
1 tit1 1,2 2,3 2,1
2 tit2 3,1 1,2 1,3
Table B (company) table c (Country) table d(regulator)
id title id title id title
1 comp1 1 country1 1 regul1
2 comp2 2 country2 2 regulator2
3 comp3 3 country3 3 regulator
I want to get a result like:
id title company country regulator
1 tit1 comp1,comp2 country2,counrtry3 regulator2,regul1
2 tit2 comp3,comp1 country1,country2 regul1,regulator3
I have made query like:
select id,title,group_concat(table B.title) AS company,group_concat(table c.title) AS
country,group_concat(table d.title) AS regulator from table A INNER JOIN table b on
find_in_set(table B.id,table A.companyid) > 0 INNER JOIN table c on find_in_set(table
c.id,table A.countryid) > 0 INNER JOIN table d on find_in_set(table d.id,table
A.regulatorid) > 0
What do I have to change to get the current result?
This is such a horrible data format that before answering, I should make you promise to change the format if you have control over it. This should really be three additional separate association/junction tables. If you are going to use a relational database, use it right.
select a.id, a.title, group_concat(distinct b.title), group_concat(distinct c.title),
group_concat(distinct d.title)
from a left outer join
b
on find_in_set(b.id, a.companyid) > 0 left outer join
c
on find_in_set(c.id, a.countryid) > 0 left outer join
d
on find_in_set(d.id, a.regulatorid) > 0
group by a.id, a.title;
But it would be much much much better to change the table layout.
I am planning to create a website similar to IMDB.com. To reduce execution time I am using the following structure. Is it okay for faster working?
Table - 1
Id Movie_name description
1 name one some description
2 name two some description
3 name three some description
Table 2
id actorname
1 name 1
2 name 2
3 name 3
4 name 4
Table 3
id movieid actorid
1 1 1
2 1 2
3 1 3
4 1 9
5 2 6
6 2 5
7 2 8
8 2 1
When I want to list actors in a movie program will retrieve actors ids from table 3 and find respective names from table 2 (using single query). When I want to list the movies of a actor it will retrieve movie ids from table 3 and find respective names from first table. Will it work properly? Any other ideas?
This will give all actors in a specified movie,
SELECT c.ID, c.actorName
FROM table1 a
INNER JOIN table3 b
ON a.ID = b.movieID
INNER JOIN table2 c
ON b.actorid = c.ID
WHERE a.ID = 1
This one will give all movies for a specified actor
SELECT a.*
FROM table1 a
INNER JOIN table3 b
ON a.ID = b.movieID
INNER JOIN table2 c
ON b.actorid = c.ID
WHERE c.ID = 1
SQLFiddle Demo (both queries)
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
UPDATE 1
This is called Relational Division
SELECT a.ID, a.Movie_Name
FROM table1 a
INNER JOIN table3 b
ON a.ID = b.movieID
INNER JOIN table2 c
ON b.actorid = c.ID
WHERE c.ID IN (1, 2, 3)
GROUP BY a.ID, a.Movie_Name
HAVING COUNT(DISTINCT c.ID) = 3
SQL of Relational Division
I suggest that you modify table3 by taking away the id field. Use the movieid and actorid together as your primary key. You might want to add other fields to this table such as name of character and order of appearance as suggested in the comment by Jermaine Xu.
I'm trying to select MerchantIDs that are the same but have different Networks values, for example:
ID MerchantID Network
1 1 A
2 1 A
3 2 B
4 2 C
5 3 D
6 3 D
In that case I would like the query to return "2" (since it's the only MerchantID that have different Networks).
Until now I have the following query:
SELECT a.MerchantID
FROM table a
JOIN table b
ON a.ID = b.ID
AND a.Network <> b.Network
AND a.MerchantID = b.MerchantID
GROUP BY a.MerchantID
Thing is table have around ~43,000 records and that query takes a LOT of time (haven't been even able to get the results).
Is there any better way to do it?
Thanks.
Try this:
SELECT MerchantID
FROM yourtable
GROUP BY MerchantID
HAVING COUNT(Distinct Network)>1
this should be faster, joins that use <> conditions are (usually) slower.
I have to select data from two tables with following criteria,
lets say there are two tables as,,
Table one
id | itemName | Quantity | companyName
1 bread 25 the Baker pvt ltd
2 butter 30 green famers
Table two
id | itemName | itemPrice
1 bread 30.50
6 jam 80.25
what I need is,
select items out of two tables which their ids are matching and the quantities of them should be multiplied by the unit price if ids are matching. The rows which don't have matching ids should be selected but their quantities should not multiplied.
SELECT o.id, o.itemName, o.companyName, o.Quantity * IFNULL(t.itemPrice, 1) total
FROM one o
LEFT JOIN two t
ON o.id = t.id
Something like this should work ...
Select a.id, a.itemName, a.companyName, a.Quantity * IFNULL(b.itemPrice,1) As total
From table1 as a
Left Join table2 as b on a.id = b.id