JOIN for a table 2 times - mysql

In my MySQL database, I have tables: group, profile and profile_titles.
Here is the structure of table group:
+----------+----------------+------------+
| group_id | title | profile_id |
| 1 | Group Title 1 | 1 |
| 2 | Group Title 2 | 1 |
| 3 | Group Title 3 | 2 |
| 4 | Group Title 4 | 2 |
| ... | Group Title 1 | ... |
| 20 | Group Title 20 | 12 |
+----------+----------------+------------+
profile_id links to FK in table profile:
+------------+------------------+
| profile_id | profile_title_id |
+------------+------------------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| ... | ... |
| 11 | 1 |
| 12 | 5 |
+------------+------------------+
profile_title_id links to FK in table profile_title:
+------------------+-----------------------+
| profile_title_id | title |
+------------------+-----------------------+
| 1 | Profile Title 1 |
| 2 | Profile Title 2 |
| 3 | Profile Title 3 |
| 4 | Profile Title 4 |
| ... | ... |
| 10 | Profile Title 10 |
+------------------+-----------------------+
I have trouble with JOIN.
Here is what i want to get as result:
+----------+----------------+-------------------+-------------------+
| group_id | title | profile_title_id | profile_title |
+----------+----------------+-------------------+-------------------+
| 1 | Group Title 1 | 1 | Profile Title 1 |
| 2 | Group Title 2 | 1 | Profile Title 1 |
| 3 | Group Title 3 | 2 | Profile Title 2 |
| 4 | Group Title 4 | 2 | Profile Title 2 |
| ... | ... | ... | ... |
| 20 | Group Title 20 | 5 | Profile Title 5 |
+----------+----------------+-------------------+-------------------+
But I am only get first 3 columns of what I want to get (group_id, title and profile_title_id). How can I add profile_title to my result? My query now:
SELECT
`group`.`group_id`,
`group`.`title`,
`profile`.`profile_title_id`
FROM `group`
LEFT JOIN `profile` ON `group`.`profile_id` = `profile`.`profile_id`
I was trying this query, but it returns an error (#1066 - Not unique table/alias: 'profile'):
SELECT
`group`.`group_id`,
`group`.`title`,
`profile`.`profile_title_id`,
`profile_title`.`title`
FROM `group`
LEFT JOIN `profile` ON `group`.`profile_id` = `profile`.`profile_id`
LEFT JOIN `profile` ON `group`.`profile_id` = `profile`.`profile_title_id`
Would love any suggestions, thanks!

It looks like you're joining profile twice when you should be joining on profile_title in the second left join:
SELECT
`group`.`group_id`,
`group`.`title`,
`profile`.`profile_title_id`,
`profile_title`.`title`
FROM `group`
LEFT JOIN `profile` ON `group`.`profile_id` = `profile`.`profile_id`
LEFT JOIN `profile_title` ON `profile`.`profile_title_id` = `profile_title`.`profile_title_id`
As for the error in your question - When joining the same table more than once you must alias the tables in order to distinguish between them.
note you can alias any table you're selecting from, basically it allows for a "shortcut" when referencing the table, or a way to uniquely identify tables in your query should there be multiple by the same name.
table aliases can be written like:
select *
from 'group' as g
in the above query, you could reference columns by g rather than group.

Please try something like:
SELECT
`group`.`group_id`,
`group`.`title`,
`profile`.`profile_title_id`,
`profile_title`.`title`
FROM `group`
LEFT JOIN `profile` ON `group`.`profile_id` = `profile`.`profile_id`
LEFT JOIN `profile_title` ON `profile`.`profile_title_id ` = `profile_title`.`profile_title_id`

Related

How to perform full text search in MySQL joining multiple tables

I'm creating e-commerce web site using MySQL. I have successfully created and inserted data to database.
Here is my database schema
table: categories table: product_types
+----+--------------+ +----+-------------+------------+
| id | name | | id | category_id | name |
+----+--------------+ +----+-------------+------------+
| 1 | Electronics | | 1 | 1 | Smartphone |
| 2 | Fashion | | 2 | 1 | Speakers |
+----+--------------+ +----+-------------+------------+
table: products
+----+-----------------+-------------+-------------------+-------+
| id | product_type_id | category_id | name | price |
+----+-----------------+-------------+-------------------+-------+
| 1 | 1 | 1 | Samsung Galaxy A3 | 300 |
| 2 | 1 | 1 | Samsung Galaxy A7 | 400 |
+----+-----------------+-------------+-------------------+-------+
table: options table: option_values
+----+-----------------+-------+ +----+-----------+------------+
| id | product_type_id | name | | id | option_id | name |
+----+-----------------+-------+ +----+-----------+------------+
| 1 | 1 | RAM | | 1 | 1 | 512 MB |
| 2 | 1 | Screen| | 2 | 1 | 1 GB |
| 3 | 1 | OS | | 3 | 3 | Android 5 |
+----+-----------------+-------+ | 4 | 3 | Android 6 |
| 5 | 2 | HD |
| 6 | 2 | FHD |
+----+-----------+------------+
table: product_option_values
+----+------------+-----------+-----------------+
| id | product_id | option_id | option_value_id |
+----+------------+-----------+-----------------+
| 15 | 1 | 1 | 1 |
| 16 | 1 | 2 | 5 |
| 17 | 1 | 3 | 3 |
| 18 | 2 | 1 | 2 |
| 19 | 2 | 2 | 6 |
| 20 | 2 | 3 | 4 |
+----+------------+-----------+-----------------+
Search must trigger through name column of each table and return name and price from products table.
The problem is that I don't know how to perform full text search joining all that tables.
Is there any easy way to do it?
You need a query that LEFT JOINs on each table to search with a condition based on fulltext search function MATCH, with a WHERE clause to filter out non-matching records. The SELECT DISTINCT ensures that you will not see duplicates.
We need to adjust manually the JOIN criteria from each table to products : option_values is the most complicated case as it does not directly references products (an additional join on product_option_values is needed, aliased pov below.
SELECT DISTINCT p.name, p.price
FROM
products p
LEFT JOIN categories c
ON MATCH(c.name) AGAINST('foo' IN NATURAL LANGUAGE MODE)
AND c.id = p.category_id
LEFT JOIN product_types pt
ON MATCH(pt.name) AGAINST('foo' IN NATURAL LANGUAGE MODE)
AND pt.category_id = p.category_id
LEFT JOIN options o
ON MATCH(o.name) AGAINST('foo' IN NATURAL LANGUAGE MODE)
AND o.product_type_id = p.product_type_id
LEFT JOIN product_option_values pov
ON pov.product_id = p.id
LEFT JOIN option_values ov
ON MATCH(ov.name) AGAINST('foo' IN NATURAL LANGUAGE MODE)
AND ov.id = pov.option_value_id
WHERE
COALESCE(c.id, pt.id, o.id, ov.id) IS NOT NULL

How can I determine which user is the top one in the specific tag?

I have a question and answer website like stackoverflow. Here is the structure of some tables:
-- {superfluous} means some other columns which are not related to this question
// q&a
+----+-----------------+--------------------------+------+-----------+-----------+
| id | title | body | type | related | author_id |
+----+-----------------+--------------------------+------+-----------+-----------+
| 1 | How can I ... | I'm trying to make ... | q | NULL | 3 |
| 2 | | You can do that by ... | a | 1 | 1 |
| 3 | Why should I .. | I'm wonder, why ... | q | NULL | 1 |
| 4 | | First of all you ... | a | 1 | 2 |
| 5 | | Because that thing ... | a | 3 | 2 |
+----+-----------------+--------------------------+------+-----------+-----------+
// users
+----+--------+-----------------+
| id | name | {superfluous} |
+----+--------+-----------------+
| 1 | Jack | |
| 2 | Peter | |
| 3 | John | |
+----+--------+-----------------+
// votes
+----+----------+-----------+-------+-----------------+
| id | user_id | post_id | value | {superfluous} |
+----+----------+-----------+-------+-----------------+
| 1 | 3 | 4 | 1 | |
| 2 | 1 | 1 | -1 | |
| 3 | 2 | 1 | 1 | |
| 4 | 3 | 2 | -1 | |
| 5 | 1 | 4 | 1 | |
| 6 | 3 | 5 | -1 | |
+----+--------+-------------+-------+-----------------+
// tags
+----+------------+-----------------+
| id | name | {superfluous} |
+----+------------+-----------------+
| 1 | PHP | |
| 2 | SQL | |
| 3 | MySQL | |
| 4 | HTML | |
| 5 | CSS | |
| 6 | C# | |
+----+------------+-----------------+
// q&aTag
+-------+--------+
| q&aid | tag_id |
+-------+--------+
| 1 | 1 |
| 1 | 4 |
| 3 | 5 |
| 3 | 4 |
| 4 | 6 |
+-------+--------+
Now I need to find top users in a specific tag. For example, I need to find Peter as top user in PHP tag. Because his answer for question1 (which has PHP tag) has earned 2 upvotes. Is doing that possible?
Try this:
select q1.title, u.id, u.name, sum(v.value) total from `q&a` q1
left join `q&atag` qt ON q1.id = qt.`q&aid`
inner join tags t ON qt.tag_id = t.id
left join `q&a` q2 ON q2.related = q1.id
left join users u ON q2.author_id = u.id
left join votes v ON v.post_id = q2.id
where t.name = 'PHP'
group by q1.id, u.id
and here is a simple divided solution:
Let us divide it into sub queries:
get the id of the tag you will search for: select id from tags where name = 'PHP'
get the questions with this tag: select 'q&aid' from 'q&aTag' where tag_id = 1.
get the ids of answers for that question: select id, author_id fromq&awhere related in (2.)
get the final query: select user_id, sum(value) from votes where post_id in (3.) group by user_id
Now combining them all give the result:
select user_id, sum(`value`) total from votes
where post_id in (
select id from `q&a` where related in (
select `q&aid` from `q&aTag` where tag_id IN (
select id from tags where name = 'PHP'
)
)
)
group by user_id
you can add this at the end if you want only one record:
order by total desc limit 1

Getting specific values from many-to-many relationships

My database looks like this, I have client accounts which are assigned to specific profiles, and I have profiles which are assigned to specific categories, like in this schema:
| categories | | profiles | | categories_map |
--------------- ------------- ----------------------------
| ID | name | | ID | name | | ID | profile_id | cat_id |
--------------- ------------- ----------------------------
| 1 | cat1 | | 1 | p1 | | 1 | 1 | 1 |
| 2 | cat2 | | 2 | p2 | | 2 | 2 | 1 |
| 3 | cat3 | | 3 | p3 | | 3 | 3 | 1 |
| 4 | p4 | | 4 | 1 | 2 |
| 5 | 3 | 2 |
| 6 | 4 | 3 |
| profiles_map |
-----------------------------
| ID | profile_id | acc_id |
-----------------------------
| 1 | 1 | 1 |
| 2 | 3 | 1 |
| 3 | 4 | 1 |
I need to get categories assigned to accounts - which means when I want to get categories for acc_id = 1, I should get categories with ID 2 and 3 ( category with ID 2 doesn't fit because it contains profile with ID 2 which isn't assigned to this account). I tried this query but it doesn't work
select cats.id from profiles_map map
right join categories_map catm on catm.profile_id = map.profile_id
right join categories cats on cats.id = catm.cat_id
where catm.profile_id in (select profile_id from profiles_map where acc_id = 1)
and map.acc_id = 1 group by cats.id;
Could anybody help me with this question?
Can you try this one?
SELECT DISTINCT C.ID
FROM profiles_map PM
INNER JOIN categories_map CM ON CM.profile_id = PM.profile_id
INNER JOIN categories C ON C.ID = CM.cat_id
WHERE PM.acc_id= 1
If you want to get only category id, Please try following query:
SELECT DISTINCT cm.cat_id FROM categories_map cm
WHERE cm.profile_id in
(SELECT profile_id FROM profiles_map WHERE acc_id = 1)
Or if want to get category name and id then , use following query:
SELECT cat.id,cat.name FROM categories cm
WHERE cat.id in (SELECT DISTINCT cm.cat_id FROM categories_map cm
WHERE cm.profile_id in
(SELECT pm.profile_id FROM profiles_map pm WHERE pm.acc_id = 1))

MySQL joining 3 tables using UNION

This question is a little long so that it would be clear, thanks in advance!
Introduction
I currently have 3 tables using a many-to-many relationship. I need to query all 3 tables and combine them into 1 table.
Problem
I have tried this query:
SELECT * FROM `login` LEFT JOIN membership ON login.id = membership.login_id UNION SELECT * FROM `login` RIGHT JOIN membership ON login.id = membership.login_id
And it returns:
+----+------+----------+
| id | name | group_id |
+----+------+----------+
| 1 | Tom | 6 |
| 2 | John | 8 |
| 3 | Jane | 4 |
+----+------+----------+
Question
I need it to also include the group_name. This is my desired output:
+----+------+----------+------------+
| id | name | group_id | group_name |
+----+------+----------+------------+
| 1 | Tom | 6 | Red |
| 2 | John | 8 | Brown |
| 3 | Jane | 4 | Purple |
+----+------+----------+------------+
Tables
login Table
A list of all users with auto-increment id
+----+------+
| id | name |
+----+------+
| 1 | Tom |
| 2 | John |
| 3 | Jane |
+----+------+
group Table
A list of all groups with the group_id and group_name
+----------+------------+
| group_id | group_name |
+----------+------------+
| 1 | Green |
| 2 | Blue |
| 3 | Yellow |
| 4 | Purple |
| 5 | Orange |
| 6 | Red |
| 7 | Pink |
| 8 | Brown |
+----------+------------+
membership Table
Stores information on which user belongs to which group
+----------+----------+
| login_id | group_id |
+----------+----------+
| 1 | 6 |
| 2 | 8 |
| 3 | 4 |
+----------+----------+
Join the group table as well and select the required fields from the tables.
SELECT l.id,l.name,m.group_id,g.group_name
FROM `login` l
LEFT JOIN `membership` m ON l.id = m.login_id
LEFT JOIN `group` g on g.group_id = m.group_id
Try this... :)
SELECT
`login`.`id`,
`login`.`name`,
`group`.`group_id`,
`group`.`group_name`
FROM
`membership`
INNER JOIN `login` ON (`membership`.`login_id` = `login`.`id`)
INNER JOIN `group` ON (`membership`.`group_id` = `group`.`group_id`)

How to select full left table and where condition match records from right table?

Please some one tell me how to do this stuff. i have two tables , i need to select entire first table(pages) and from sencond table where user_id = 1
table 1: page
--------------------------------------
page_id | page_url | details |
--------------------------------------
1 | xxxx | wdredrr |
2 | yyyy | rdsacsa |
3 | zzzz | rscsacc |
4 | aaaa | xdsxsxs |
5 | bbbb | drxcraa |
--------------------------------------
table 2: control
-------------------------------------
control_id | page_id | user_id |
-------------------------------------
1 | 1 | 1 |
2 | 3 | 1 |
3 | 4 | 1 |
4 | 1 | 2 |
5 | 2 | 2 |
-------------------------------------
and this is what expecting output.
expecting output
--------------------------------------------------------------
page_id | page_url | details | control_id | user_id |
--------------------------------------------------------------
1 | xxxx | wdredrr | 1 | 1 |
2 | yyyy | rdsacsa | null | null |
3 | zzzz | rscsacc | 2 | 1 |
4 | aaaa | xdsxsxs | null | null |
5 | bbbb | drxcraa | 3 | 1 |
--------------------------------------------------------------
pages JOIN control ON page.page_id = control.page_id WHERE control.user_id = '1'
please someone help to solve this problem. i tried with LEFT JOIN and RIGHT JOIN but i get user_id = 1 matched rows only
Inner join will check if the related data is available with the join condition in the related tables and hence it will filter out unmatched data. You need to use left join and the conditions in the joining clause something as
select
p.*,
c.control_id,
c.user_id
from page p left join control c on c.page_id = p.page_id and c.user_id = 1
order by p.page_id;
Put the your where clause in the on clause and you should get the expected result:
select * from pages JOIN control ON page.page_id = control.page_id AND control.user_id = '1'
Try this
SELECT p.page_id, p.page_url, p.details, IF(c.user_id=1,c.control_id,NULL), IF(c.user_id=1,c.user_id,NULL) FROM page p LEFT JOIN control c ON(c.page_id=p.page_id)