mysql request using join and group_concat - mysql

I have three tables "names", "groups", "tasks"
"names"
| nid | name |
| 1 | John |
| 2 | Jim |
| 3 | Jerry |
"groups"
| gid | nid |
| 1 | 1 |
| 1 | 2 |
| 2 | 2 |
| 2 | 3 |
"tasks"
| tid | gid |
| 1 | 2 |
| 2 | 1 |
I want to get a list of names, that belong to a task, like this:
| tid | names |
| 1 | Jim,Jerry |
| 2 | John,Jim |
I successfully tried:
SELECT t.tid,n.name
FROM tasks t
LEFT JOIN groups g ON g.gid=t.gid
LEFT JOIN names n ON n.nid=g.nid
This works so far, but the names are in single outputs so I tried to use GROUP_CONCAT(), but this does not work. I just get the first task with the wrong names!?!?
SELECT t.tid,GROUP_CONCAT(n.name)
FROM tasks t
LEFT JOIN groups g ON g.gid=t.gid
LEFT JOIN names n ON n.nid=g.nid
I have never used GROUP_CONCAT() before. It works well, when using it in a single SELECT without joins. A short explanation what I did wrong, would be nice.

When using group_concat you need to group your results.
Add group by t.id at the end of your query.

Related

In a Join, How to Ensure Each Group In Table B Joins to Every Row in Table A

My SQL dialect is MySQL. I am creating a view on two tables.
I have TableA which looks like this:
| date | value |
|------|-------|
| 1 | 100 |
| 2 | 150 |
I have TableB which looks like this:
| date | group | name |
|------|-------|-------|
| 1 | d | alice |
| 1 | e | bob |
| 2 | d | clark |
| 2 | e | mick |
I want to do a join and combine them on the date column, in such a way the each group in B gets a join on A. To be more clear, here's what the output data should look like:
| date | group | value | name |
|------|-------|-------|-------|
| 1 | d | 100 | alice |
| 1 | e | 100 | bob |
| 2 | d | 150 | clark |
| 2 | e | 150 | mick |
So this is a pretty contrived example, just to make it easy to read in markdown. But some details about my actual problem:
I have a large of number of groups, so many nested derived tables is not feasible, and would slow the view query time too much.
I need to generate columns that are some function of both tables (e.g. some output like value + name, which is obviously nonsensical with this example's types)
I have tried using:
SELECT value, name, group
FROM TableA
RIGHT OUTER JOIN TableB
ON TableA.date = TableB.date
The output in this case just takes one of the groups, and ditches the rest.
What is the syntax for this?
Based on the data sample you've shared, it looks like you're looking for an INNER JOIN instead of a RIGHT JOIN.
SELECT value, name, group
FROM TableA
JOIN TableB
ON TableA.date = TableB.date

How can I get a total count of items?

I'm trying to figure out a MYSQL string and my noob-ness is getting in my way. I'm trying to count the total number of teams per phase.
Tables to consider:
phases
+----+------------+
| id | phase_name |
+----+------------+
| 1 | start |
| 2 | middle |
| 3 | end |
| 4 | finish |
+----+------------+
teams
+----+-----------+----------+
| id | team_name | phase_id |
+----+-----------+----------+
| 1 | team1 | 2 |
| 2 | team2 | 3 |
| 3 | team3 | 3 |
| 4 | team4 | 4 |
| 4 | team5 | 3 |
+----+-----------+----------+
Desired result
+----------+------------+-----------+
| phase_id | phase_name | tot_teams |
+----------+------------+-----------+
| 1 | start | NULL |
| 2 | middle | 1 |
| 3 | end | 3 |
| 4 | finish | 1 |
+----------+------------+-----------+
I've tried:
SELECT
T.phase_id, P.phase_name, COUNT(*) AS tot_teams
FROM
teams T
LEFT JOIN
phases P ON P.id = T.phase_id
GROUP BY
phase_id;
but that only shows the affected phase_id's...and I'm hoping to get ALL phase_id's in a table. I also tried:
SELECT
P.phase_name, T.phase_id, COUNT(*)
FROM
teams T
RIGHT JOIN
phases P on P.`id` = T.`phase_id`
GROUP BY
P.id
but that shows invalid data. (For example, phase_id has a qty of 1 but doesn't show up in the teams table.
Can you point me in the right direction?
Thanks!
The RIGHT JOIN is correct, but you need to use COUNT(T.phase_id) instead of COUNT(*). Otherwise, you're counting the row containing NULL that's generated for the phase with no teams.
Most people prefer to use LEFT JOIN, putting the master table first.
SELECT P.phase_name, P.phase_name, COUNT(T.phase_id)
FROM phase AS P
LEFT JOIN teams AS T ON P.id = T.phase_id
GROUP BY P.id

How to write a join query for many to many relationship? for dictionary project

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 linked to a single meaning.
And also I have to write a query to select all meaning 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 |
+---------+-----------+
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 |
+----+----------+
| A | X |
| A | Y |
| A | Z |
+----+----------+
I don't know how to write a join query for this scenario.
SELECT wt.word, mt.meaning
FROM word_table wt
INNER JOIN word_meaning_table wmt
ON wt.id = wmt.word_id
INNER JOIN meaning_table mt
ON wmt.meaning_id = mt.id
WHERE wt.word = 'A'
Follow the link below for a working demo:
SQLFiddle
Try
select word, meaning
from word_table
join meaning_table on word_table.id=meaning_table.id;

Is this possible using inner joins in MySQL?

I'm stuck on trying to build a query that will include a given order_reference cover file from the data sample below only if ALL of the print_item_qty values of the files under the same order_reference are equal to 5.
Is this possible using joins or is this outside the remit of a single query?
I've tried building inner joins but cannot work out how to restrict the results so that I only get a cover row when all the component parts of an order have equal values in the print_item_qty column.
Here is the base SELECT query and sample data:
SELECT c1.`order_id`,c1.name1,c1.name2,c1.`print_item_qty`,c1.`sub_item_type`,
c1.`order_reference` FROM print_items;
+--------------+-------+---------+----------------+---------------+-----------------+
| order_id | name1 | name2 | print_item_qty | sub_item_type | order_reference |
+--------------+-------+---------+----------------+---------------+-----------------+
| 000003201875 | Jason | Bramley | 5 | cover | 1875 |
| 000003201875 | Jason | Bramley | 5 | inner | 1875 |
| 000003201875 | Jason | Bramley | 1 | card | 1875 |
| 000003201876 | Jason | Bramley | 5 | cover | 1876 |
| 000003201876 | Jason | Bramley | 5 | inner | 1876 |
+--------------+-------+---------+----------------+---------------+-----------------+
My desired result for the above sample data would be only the following row:
+--------------+-------+---------+----------------+---------------+-----------------+
| order_id | name1 | name2 | print_item_qty | sub_item_type | order_reference |
+--------------+-------+---------+----------------+---------------+-----------------+
| 000003201876 | Jason | Bramley | 5 | cover | 1876 |
+--------------+-------+---------+----------------+---------------+-----------------+
Any help anyone could give to point me in the right direction would be greatly appreciated.
Many thanks.
So you want to verify that you only select data for orders for which the print_item_qty = 5 for all sub_item_type in that order_reference.
To do this, use a subsquery like
SELECT order_reference,
MAX(print_item_qty),
MIN(print_item_qty)
FROM print_items
GROUP BY order_reference
HAVING MAX(print_item_qty) = 5
AND MIN(print_item_qty) = 5
And join to your original dataset. The subquery will restrict to the ids you want, and joining back will return all rows associated with the order_references for which print_item_qty = 5 for every sub_item_type, eg,
SELECT c1.`order_id`,
c1.name1,
c1.name2,
c1.`print_item_qty`,
c1.`sub_item_type`,
c1.`order_reference`
FROM print_items AS c1
INNER JOIN (SELECT order_reference, MAX(print_item_qty), MIN(print_item_qty) FROM print_items
GROUP BY order_reference HAVING MAX(print_item_qty) = 5 AND MIN(print_item_qty) = 5) AS b
ON c1.order_reference = b.order_reference

How can I join two tables, keeping rows that do not meet the JOIN condition?

ticket
+----------+--------+
| ticketID | assign |
+----------+--------+
| 1015 | NULL |
| 1020 | James |
| 1021 | Nick |
+----------+--------+
staffinfo
+---------+-------+
| staffID | staff |
+---------+-------+
| 1 | Jane |
| 2 | James |
| 3 | Nick |
| 4 | Cole |
+---------+-------+
SELECT staff,COUNT(*) as count FROM staffinfo,ticket
WHERE ticket.assign = staffinfo.staff
GROUP BY staff
result:
+-------+-------+
| staff | count |
+-------+-------+
| James | 1 |
| Nick | 1 |
+-------+-------+
Works fine, but infact i need smthing like:
+-------+-------+
| staff | count |
+-------+-------+
| James | 1 |
| Nick | 1 |
| Jane | 0 |
| Cole | 0 |
+-------+-------+
COUNT doesnt count records that arent in the table, and since i just started learning SQL, i wanna ask if theres a way to count as the above result?
you should be using LEFT JOIN
SELECT a.staff, COUNT(b.assign) as count
FROM staffinfo a
LEFT JOIN ticket b
ON b.assign = a.staff
GROUP BY a.staff
SQLFiddle Demo
To fully gain knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
Use LEFT JOIN
The LEFT JOIN keyword returns all rows from the left table (table_name1), even if there are no matches in the right table (table_name2).
SELECT staffinfo.staff, count(ticket.assign)
FROM staffinfo
LEFT JOIN ticket
ON ticket.assign =staffinfo.staff
GROUP BY staffinfo.staff
The LEFT JOIN keyword returns all the rows from the left table (staffinfo), even if there are no matches in the right table (ticket).