A simple many to many SQL example - mysql

I'm trying to figure out a good way of doing an SQL query that returns a table of user names and their choices (there are a set number of choices and a user can have many choices) as in the example below. I haven't been able to find a good simple example of this (other than how the relationship is laid out). Is this solution viable or is there a better way of doing it? I seem to get the table I'm looking for.
SELECT
users.name,
choices.choice as choice
FROM
choice
JOIN relation ON choice.choice_id = relation.choice_id
JOIN users ON users.name_id = relation.user_id;
Gives me the correct table:
+------+--------+
| name | choice |
+------+--------+
| amy | a |
| amy | b |
| amy | c |
| joe | d |
+------+--------+
The simple database looks like this:
Users
+------+---------+
| name | name_id |
+------+---------+
| amy | 1 |
| joe | 2 |
+------+---------+
Choices
+----------+---------+
| choice_id| choice |
+----------+---------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |
+----------+---------+
Relation
+----------+---------+
| choice_id| user_id |
+----------+---------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
+----------+---------+

Related

MySQL - Select result where field is empty or doesn't exists

I've got a MySQL table with movies and flexible data. Not every movie has the same fields (filled).
However I want to do a query that finds all movies where a specific field is empty or doesn't exist.
This is an example of what my database table looks like:
| id | article_id | fieldname | content |
|----|------------|-----------|------------------|
| 1 | 1 | title | Star Wars |
| 2 | 1 | director | George Lucas |
| 3 | 1 | actor | Harrison Ford |
|----|------------|-----------|------------------|
| 4 | 2 | title | Jurassic Park |
| 5 | 2 | duration | Jeff Goldblum |
|----|------------|-----------|------------------|
| 6 | 3 | title | E.T. |
| 7 | 3 | actor | |
| 8 | 3 | director | Steven Spielberg |
How can I get all movies where "actor" is empty or doesn't exist?
SELECT * FROM table_name WHERE content IS NULL AND fieldname = 'actor'
should do the trick.

Query equivalent to two group by's without a subquery?

I'm trying to run a report on User ACL's. We use MYSQL and my we're prohibited from using subqueries for performance reasons. The goal is to turn this:
--------------------------------
| userName | folderID | roleID |
--------------------------------
| gronk | 1 | 1 |
| gronk | 2 | 2 |
| gronk | 4 | 2 |
| tbrady | 1 | 2 |
| jedelman | 1 | 1 |
| jedelman | 2 | 1 |
| mbutler | 1 | 2 |
| mbutler | 2 | 2 |
| bill | 1 | 3 |
| bill | 2 | 3 |
| bill | 3 | 3 |
| bill | 4 | 3 |
--------------------------------
Into this:
------------------------
| Lowest Role | Number |
------------------------
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
------------------------
I can see how to do it with a subquery. The inner query would do a group by on userName with a min(roleID). Then the outer query would do a group by on the lowest role and count(*). But I can't see how to do it without a subquery.
Also, if it helps I created a SQL Fiddle that has the data above.
I found a solution using a left join:
select UFM.roleID, count(distinct UFM.userName)
from UserFolderMembership UFM
left join UserFolderMembership UFM2 on
UFM.userName = UFM2.userName and
UFM.roleID > UFM2.roleID
where
UFM2.userName is null
group by
UFM.roleID

Combine two tables into one table

I need to join user table with all user images in one row, like this
table user
+----+---------------+
|id | name |
+----+---------------+
| 1 | Mike |
| 2 | Jerry |
| .. | ..... |
+----+---------------+
table image
+------+---------+---------+
| id | user_id | img |
+------+---------+---------+
| 1 | 1 | img_1 |
| 2 | 1 | img_2 |
| 3 | 1 | img_3 |
| 4 | 2 | img_4 |
| .. | .... | ..... |
+------+---------+---------+
I need to generate SQL results like this
+------+--------+----------+----------+----------+
| id | name | img1 | img2 | img3 |
+------+--------+----------+----------+----------+
| 1 | Mike | img_1 | img_2 | img_3 |
+------+--------+----------+----------+----------+
| ... | .... | .... | .... | .... |
+------+--------+----------+----------+----------+
That's not natively supported in mysql, however you could use a pivot to create exactly your result, however that requires some hardcoding I'd avoid if possible.
A simple solution for your task could be using GROUP_CONCAT(), which would produce a resultset like
+------+--------+----------+----------+----------+
| id | name | images |
+------+--------+----------+----------+----------+
| 1 | Mike | img_1;img_2;img_3 |
+------+--------+----------+----------+----------+
| ... | .... | |
+------+--------+----------+----------+----------+
If that's good enough, you can achieve that with
SELECT a.id, a.name, GROUP_CONCAT(b.img) images
FROM user a
INNER JOIN image b ON a.id = b.user_id
GROUP BY b.user_id;

I need help for many to many relation query

I have working on database for dictionary project. I have to store a word and meaning with many to many relationship.
Below I have mentioned the sample with my table structure. I hope the table structure is right, but I don't know how to select all meanings for single word while user searching.
And also I have to write a query to select all word and synonyms linked to a single meaning. And also I have to write a query to select all meaning and synonyms linked to a single word.
word_table
+----+------+
| id | word |
+----+------+
| 1 | A |
| 2 | B |
| 3 | C |
+----+------+
meaning_table
+----+--------+
| id | meaning|
+----+--------+
| 1 | X |
| 2 | Y |
| 3 | Z |
+----+--------+
word_meaning_table
+---------+-----------+
| word_id | meaning_id|
+---------+-----------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 3 |
| 3 | 2 |
| 3 | 3 |
+---------+-----------+
synonyms_table
+----+--------+
| id | synonys|
+----+--------+
| 1 | aa |
| 2 | bb |
| 3 | cc |
+----+--------+
word_synonyms_table
+---------+-----------+
| word_id | synonym_id|
+---------+-----------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
+---------+-----------+
Expected output should be like this.
If user searching for a word "A" in word table the result should be
Result for word "A"
+----+----------+---------+
| word| meaning | synonys |
+----+----------+---------+
| A | X | aa |
| A | Y | bb |
| A | Z | cc |
+----+----------+---------+
You just need many joins:
SELECT w.word,m.meaning,s.synonys
FROM word_table w
INNER JOIN word_meaning_table wm
ON(w.id = wm.word_id)
INNER JOIN meaning_table m
ON(wm.meaning_id = m.id)
INNER JOIN word_synonyms_table ws
ON(w.id = ws.word_id)
INNER JOIN synonyms_table s
ON(ws.synonym_id = s.id)
Let me reffer you to this document that explain all about join syntax's.

mySQL Table Join - Wrong Answer

I'm quite new to mySQL queries and struggling to achieve the result I require.
I have two tables of user information that I need to present. The tables are as follows:
users
+----+------------------+
| id | email |
+----+------------------+
| 1 | joe#hotmail.com |
| 2 | john#hotmail.com |
| 3 | fred#hatmail.com |
+----+------------------+
user_detail
+----------+--------+--------+
| detailid | userid | detail |
+----------+--------+--------+
| 1 | 1 | Joe |
| 2 | 1 | Soap |
| 1 | 2 | John |
| 2 | 2 | Doe |
| 1 | 3 | Fred |
| 2 | 3 | Bloggs |
+----------+--------+--------+
I have constructed the following query which joins the tables:
SELECT id, detail , email
FROM users
LEFT JOIN user_detail
ON users.id=user_detail.userid
ORDER by id
The query produces this result:
+--------+--------+------------------+
| userid | detail | email |
+--------+--------+------------------+
| 1 | Joe | joe#hotmail.com |
| 1 | Soap | joe#hotmail.com |
| 2 | John | john#hotmail.com |
| 2 | Doe | john#hotmail.com |
| 3 | Fred | fred#hatmail.com |
| 3 | Bloggs | fred#hatmail.com |
+--------+--------+------------------+
What I'm struggling to achieve is this:
+--------+---------+---------+------------------+
| userid | detail1 | detail2 | email |
+--------+---------+---------+------------------+
| 1 | Joe | Soap | joe#hotmail.com |
| 2 | John | Doe | john#hotmail.com |
| 3 | Fred | Bloggs | fred#hatmail.com |
+--------+---------+---------+------------------+
Could you please help and point me in the right direction?
SELECT id,
MAX(CASE WHEN detaildid=1 THEN detail END) as detail1,
MAX(CASE WHEN detaildid=2 THEN detail END) as detail2,
email
FROM users
LEFT JOIN user_detail
ON users.id=user_detail.userid
GROUP BY id,email
ORDER by id
This can be written dynamically if you have many detailids.
You can join the same table twice, once for detail id 1 and another instance for detail id 2
SELECT id, d1.detail, d2.detail, email
FROM users u
LEFT JOIN user_detail d1
ON u.id = d1.userid
AND d1.detailid = 1
LEFT JOIN user_detail d2
ON u.id = d2.userid
AND d2.detailid = 2
ORDER BY ID