I have something like this
2 tables:
videos
members
In the members table I have the name of each member:
1 Tom
2 Bob
3 Zack
4 Dan
5 Casey
In the videos table I have a column named members and I have the names in there seperated by commas
1. Tom,Dan
2. Casey,Zack,Bob
3. Tom,Casey,Dan,Zack
4. Zack,Bob,Dan
I'm trying to display how many times each member appears to get these results:
1 Tom = 2
2 Bob = 2
3 Zack = 3
4 Dan = 2
5 Casey = 2
Do I need to do something like SELECT SUM(members) WHERE and use LIKE?
I would strongly suggest to normalize your data as others suggested.
Based on your current design you can use FIND_IN_SET to accomplish the result you want.
SELECT
M.id,
M.name,
COUNT(*) total
FROM members M
INNER JOIN videos V ON FIND_IN_SET(M.name,V.members) > 0
GROUP BY M.name
ORDER BY M.id
See Demo
Running this query on your given data set you will get output like below:
| id | name | total |
|----|-------|-------|
| 1 | Tom | 2 |
| 2 | Bob | 2 |
| 3 | Zack | 3 |
| 4 | Dan | 3 |
| 5 | Casey | 2 |
A must read
Is storing a delimited list in a database column really that bad?
More
This is how your vidoes table would look like if you normalize your data:
videos
id member_id
One way to go is to join the two tables, based on a like expression:
SELECT members.name, count (*) as counter from members inner join videos
ON videos.members like CONCAT('%,',members.name,',%')
GROUP BY members.name;
But I think the better solution will be like #e4c5 said in the comment - you need to normalize the data. the videos table should look like:
+---+-------+
|ID | MEMBER|
+---+-------+
| 1 | Tom |
| 1 | Dan |
| 2 | Casey |
| 2 | Zack |
| 2 | Bob |
| 3 | Tom |
| 3 | Casey |
| 3 | Dan |
| 3 | Zack |
| 4 | Zack |
| 4 | Bob |
| 4 | Dan |
+---+-------+
That way, you can simply count on this table
Related
Consider the following sample table from a soccer tournament (let's call this table matches)
+----------+---------+--------------+
| match_id | club_id | goals_scored |
+----------+---------+--------------+
| 1 | 1 | 1 |
| 1 | 2 | 0 |
| 2 | 1 | 1 |
| 2 | 3 | 1 |
| 3 | 1 | 0 |
| 3 | 4 | 2 |
| 4 | 2 | 2 |
| 4 | 3 | 4 |
| 5 | 2 | 4 |
| 5 | 4 | 0 |
| 6 | 3 | 1 |
| 6 | 4 | 1 |
+----------+---------+--------------+
The resulting table we want should give us each club's total goals scored AND goals conceded:
+---------+--------------+----------------+
| club_id | goals_scored | goals_conceded |
+---------+--------------+----------------+
| 1 | 2 | 4 |
| 2 | 6 | 4 |
| 3 | 6 | 4 |
| 4 | 3 | 5 |
+---------+--------------+----------------+
Getting goals scored is straight forward enough...
SELECT SUM(goals_scored),
club_id
FROM matches
GROUP BY club_id
but I am absolutely flummoxed as to how to get it for each team's opponents.
I could, of course, construct a pretty complex array of subqueries to get there. If this were application-side work I'd likely just stuff it in a loop and iterate over each club to get there, but my use case requires a SQL answer if possible. Any thoughts?
edit: also if anyone has any better ideas on how to title this question, I'm all ears - I'm not really sure exactly how to describe this problem in the first place.
We can use a self-join approach here:
SELECT
m1.club_id,
SUM(m1.goals_scored) AS goals_scored,
SUM(m2.goals_scored) AS goals_conceded
FROM matches m1
INNER JOIN matches m2
ON m2.match_id = m1.match_id AND
m2.club_id <> m1.club_id
GROUP BY
m1.club_id
ORDER BY
m1.club_id;
This approach brings the goals conceded by each club to the other club, for each match, into a single row. We then just aggregate by club to get the two sums.
I have a bunch of articles
+-----------+-------+
| ArticleID | Name |
+-----------+-------+
| 1 | Bla |
| 2 | Blub |
| 3 | Test |
+-----------+-------+
And Prodcutgroups:
+-----------+--------------+
| ProductGroupID | Name |
+-----------+--------------+
| 4 | Group A |
| 5 | Group B |
| 6 | Group C |
+-----------+--------------+
And a link table (M:N relation) that links articles with product-groups. Each article can be in many product-groups at the same time but only once per group:
+-----------+----------------+
| ArticleID | ProductGroupID |
+-----------+----------------+
| 1 | 4 |
| 1 | 5 |
| 2 | 5 |
| 2 | 6 |
| 3 | 4 |
| 3 | 6 |
+-----------+----------------+
My problem is now that I need a query that lets me find out articles that are MISSING in product-group with ID 4.
Usually I would write a PHP Script that loops entire table and checks for values and remembers if product-group-id 4 was not found.
But this seems very sophisticated and annoying as I have this kind of szenario more often here and there.
I cannot use WHERE ProductGroupID NOT IN(4) because when the article is assigned to OTHER product-groups it will find that rows and
the result will NOT tell me wether the article is in this specific group or not.
The result would need to give me only!! Article-ID: 2 as its not in Product-Group with ID 4
I appreciate any helpful advice!
One option, using exists logic:
SELECT a.Name
FROM articles a
WHERE NOT EXISTS (SELECT 1 FROM link l
WHERE l.ArticleID = a.ArticleID AND l.ProductGroupID = 4);
Read in plain English, the above query says to return the name of article for which we cannot find an entry in the link table associated with ProductGroupID = 4.
I need to write a query listing the name of the staff member(s) who supervise(s) the
highest number of students. The result should also display the number of students.
The query should also work in situations when more than one supervisor has
highest students (e.g. 2 supervisors each having 10 students, 10 being highest).
Every post on stackoverflow I have read about getting the most common value all talk about just listing values by frequency of occurence and then using LIMIT to only show the top one. However I need to do it in such a way that it will show the highest one and any others that are equal to it and it has to be dynamic for a result list of any length.
There is 2 separate tables as below so I figured the query would be something like
Students table
+------------------+----------+
| S_FIRST | F_ID |
+------------------+----------+
| Tammy | 1 |
| jorge | 1 |
| john | 1 |
| mike | 2 |
| lisa | 4 |
| ni | 3 |
faculty table
+------------------+----------+
| F_FIRST | F_ID |
+------------------+----------+
| Teresa | 1 |
| mark | 2 |
| colin | 3 |
| jonnel | 4 |
| james | 5 |
SELECT F_FIRST, COUNT(student.F_ID) AS value_occurrence
from faculty, student
group by F_FIRST
ORDER BY value_occurrence DESC;
But that just gives the below output.
F_FIRST VALUE_OCCURRENCE
--------------- ----------------
Jonnel 6
Mark 6
James 6
Colin 6
Teresa 6
The expected output is
F_FIRST VALUE_OCCURRENCE
--------------- ----------------
Teresa 3
I have a table like this:
// friends
+----+---------+--------+
| id | user_id | friend |
+----+---------+--------+
| 1 | 1 | Peter |
| 2 | 1 | Martin |
| 3 | 2 | Jack |
| 4 | 1 | Barman |
| 5 | 3 | Peter |
| 6 | 1 | Jack |
| 7 | 3 | David |
| 8 | 2 | David |
| 9 | 3 | Martin |
+----+---------+--------+
Now I have two user_ids. For example 1 and 3. Now I want to match the rows which have common friends. So this is expected result:
| Peter |
| Martin |
Because Peter and Martin are common for both ids 1 and 3.
Is doing that possible by pure sql ?
You can do a self-join of the friends table, with the following three conditions being required to match records from both sides of the join:
The user_id from the first table is 1
The user_id from the second table is 3
The friends match (i.e. are shared by both sides)
SELECT t1.friend
FROM friends t1
INNER JOIN friends t2
ON t1.user_id = 1 AND
t2.user_id = 3 AND
t1.friend = t2.friend
If you have indices setup properly, I would expect this to run faster than an aggregation approach.
Demo here:
Rextester
Try this:
SELECT friend
FROM friends
WHERE user_id IN (1, 3)
GROUP BY friend HAVING COUNT(DISTINCT friend) = 2;
Another way
SELECT friend
FROM t
GROUP BY friend
HAVING SUM(user_id =1)>0
AND SUM(user_id =3)>0
I have 2 tables like this:
Table person
id | name
---------
1 | john
2 | mike
3 | carl
4 | keny
5 | anna
Table vehicle
owner | vechicle
----------------
1 | RTA457
3 | GSW684
3 | GKI321
3 | SNE798
5 | YTT662
So, I want to make a query joining both tables, something like this:
SELECT * FROM person LEFT JOIN vehicle ON person.id=vehicle.owner
Getting these results
id | name | owner | vechicle
----------------------------
1 | john | 1 | RTA457
2 | mike | NULL | NULL
3 | carl | 3 | GSW684
3 | carl | 3 | GKI321
3 | carl | 3 | SNE798
4 | keny | NULL | NULL
5 | anna | 5 | YTT662
Finally, I want to limit it to 3 persons, showing all their vehicles, like this:
id | name | owner | vechicle
----------------------------
1 | john | 1 | RTA457
2 | mike | NULL | NULL
3 | carl | 3 | GSW684
3 | carl | 3 | GKI321
3 | carl | 3 | SNE798
There is any way to do it?
May help with a subquery
SELECT
*
FROM
(SELECT * FROM person LIMIT 3) t
LEFT JOIN vehicle ON t.id = vehicle.owner
Didn't try it, but something like this:
SELECT * FROM person
LEFT JOIN vehicle ON person.id = vehicle.owner
WHERE person.id IN (SELECT ID FROM PERSON LIMIT 3);
You could simply have your query as such:
SELECT * FROM person LEFT JOIN vehicle ON person.id=vehicle.owner LIMIT 10;
This SO could be handy as well. Hope this helps!