Can this be done in a single SQL query? - mysql

I have a table lists with columns list_id, name, etc. I have another table members with columns user_id and list_id (with a unique index on the pair (user,list)).
Now, I want to generate a three-column output: list_id, name, membership where membership is 0 or 1 depending on whether or not the current user is member of the list (i.e. there is an entry for that user on that list). If I do
SELECT
list_id, name, 1
FROM
lists
LEFT JOIN members ON (lists.list_id = members.list_id AND members.user_id=2)
I will get the correct 1-rows for user 2, but the 0-rows will simply be gone. Is there a nice way to obtain my desired effect with a single MySQL query?

I think you want something like this:
SELECT list_id, name, (m.list_id is not null) as MemberOnList
FROM lists l LEFT JOIN
members m
ON l.list_id = m.list_id and
m.member_id = #CURRENTUSER;

Related

SQL select users that belong to two groups

I have a list of persons in a table. I then have another table where I correlate each person to one or more groups. Some persons have only one entry in the groups table but some have multiple.
I am now trying to SELECT list of persons that are in two specific groups. Person must be in BOTH groups in order to qualify.
My table with the basic information on the persons is base and the table with the group correlation is groups_registration. In fact I also have a third table where the groups names and further information are stored but it is not required for this query.
The groups I am trying to gather in this example are 4 and 11.
What I tried initially was:
SELECT base.*, groups_registration.person_id, groups_registration.group_id
FROM base
INNER JOIN groups_registration
ON base.id = groups_registration.person_id
WHERE (groups_registration.group_id = '4' AND groups_registration.group_id = '11')
ORDER BY base.name
This did not get my any response, I assume because no single row contains both group_id = 4 and group_id 11.
I have been searching through stackoverflow with no joy. Do you guys have any ideas?
Obviously, no row has both values. Use group by:
SELECT gr.person_id, groups_registration.group_id
FROM groups_registration gr
WHERE gr.group_id IN (4, 11)
GROUP BY gr.person_id
HAVING COUNT(DISTINCT gr.group_id) = 2;
I'll let you figure out how to join in the additional information from base.
Notes:
Use table aliases to make it easier to write and read queries.
Presumably, the ids are numbers. Compare numbers to numbers. Only use single quotes for date and string constants.
IN is better than long chains of OR/=.
You can use joins as shown below:
SELECT A.*, B.person_id, B.group_id
FROM base A
INNER JOIN
(SELECT gr.person_id, groups_registration.group_id
FROM groups_registration gr
WHERE gr.group_id IN (4, 11)
GROUP BY gr.person_id
HAVING COUNT(DISTINCT gr.group_id) = 2) B
ON A.id = B.person_id;
This will give you all the desired fields.

Creating an SQL View With Calculations From Multiple Tables

So I have two tables that I need information from. I have a
ballot_table(vote CHAR(30), username CHAR(30)) that has the name of the candidate each username voted for. I also have another table with a list of the candidates. I need someway to return the list of candidates with the corresponding amount of times there name appears in ballot_table in the same query. Thanks!
This is a horrible design but here is how you do it:
select count(*) as votes, vote as [candidate]
from ballot_table
where ucase(vote) in (select ucase(item) from table_with_list_of_candidates)
group by ucase(vote)
a better design would have the list of candidates table include a key and then just have the key in the ballot_table with a varchar for a write in (if needed).
You can do this with an Outer Join and a Group By. I'm assuming the field name in the candidate table is Name.
Select c.Name, Count(Distinct b.UserName) Votes
From ballot_table b
Right Join candidate c On c.Name = b.Vote
Group By c.Name
This would only return the total votes for the candidates you have in your Candidate table. Any other "write-in" vote wouldn't be included.

SQL Comment Grouping

I have two table in MySQL
Table 1: List of ID's
--Just a single column list of ID's
Table 2: Groups
--Group Titles
--Members **
Now the member field is basically a comments field where all the ID's that are part of that group are listed. So for instance one whole field of members looks like this:
"ID003|ID004|ID005|ID006|ID007|ID008|... Etc."
There they can be up to 500+ listed in the field.
What I would like to do is to run a query and find out which ID's appear in only three or less groups.
I've been taking cracks at it, but honestly I'm totally lost. Any ideas?
Edit; I misunderstood the question the first time, so I'm changing my answer.
SELECT l.id
FROM List_of_ids AS l
JOIN Groups AS g ON CONCAT('|', g.members, '|') LIKE CONCAT('%|', l.id, '|%')
GROUP BY l.id
HAVING COUNT(*) <= 3
This is bound to perform very poorly, because it forces a table-scan of both tables. If you have 500 id's and 500 groups, it must run 250000 comparisons.
You should really consider if storing a symbol-separated list is the right way to do this. See my answer to Is storing a delimited list in a database column really that bad?
The proper way to design such a relationship is to create a third table that maps id's to groups:
CREATE TABLE GroupsIds (
memberid INT,
groupid INT,
PRIMARY KEY (memberid, groupid)
);
With this table, it would be much more efficient by using an index for the join:
SELECT l.id
FROM List_of_ids AS l
JOIN GroupsIds AS gi ON gi.memberid = l.id
GROUP BY l.id
HAVING COUNT(*) <= 3
select * from
(
select ID,
(
select count(*)
From Groups
where LOCATE(concat('ID', a.id, '|'), concat(Members, '|'))>0
) as groupcount
from ListIDTable as a
) as q
where groupcount <= 3

Left outer join with count not returning rows with 0 count

I'm trying to return a simple list of all items in table A (groups) with a count of the corresponding number of users in column B (users_groups) and I can't figure out where I'm going wrong.
SELECT groups.gid, name, COUNT(uid) AS groupcount
FROM groups
LEFT OUTER JOIN users_groups ON groups.gid = users_groups.gid
WHERE aid = ?
I currently have two groups, one of which has three users. That row returns with the proper value in groupcount but I'm missing what should be the second row displayed with a 0 groupcount. Can anyone point me in the right direction? Thanks!
Presumably this is because aid is in users_groups and not in groups.
The left outer join will create a row where this is NULL. Any comparison other than "is null" will result in no match.
You can fix this by doing something like:
where coalesce(aid, ??) = ??
If that is the intention of your query.
Or, another alternative, is that you don't have a group by in your query. Try this:
SELECT groups.gid, name, COUNT(uid) AS groupcount
FROM groups LEFT OUTER JOIN
users_groups
ON groups.gid = users_groups.gid
WHERE aid = ?
group by groups.gid, name
Mysql has the disfeature that you can include unaggregated columns in the SELECT clause. However, it only groups by what is in the group by. Since you have nothing specified for grouping, it is producing one row over all the data. The values of gid and name are arbitrarily chosen from the input.

MySQL joins and COUNT(*) from another table

I have two tables: groups and group_members.
The groups table contains all the information for each group, such as its ID, title, description, etc.
In the group_members table, it lists all the members who are apart of each group like this:
group_id | user_id
1 | 100
2 | 23
2 | 100
9 | 601
Basically, I want to list THREE groups on a page, and I only want to list groups which have MORE than four members. Inside the <?php while ?> loop, I then want to four members who are apart of that group. I'm having no trouble listing the groups, and listing the members in another internal loop, I just cannot refine the groups so that ONLY those with more than 4 members show.
Does anybody know how to do this? I'm sure it's with MySQL joins.
MySQL use HAVING statement for this tasks.
Your query would look like this:
SELECT g.group_id, COUNT(m.member_id) AS members
FROM groups AS g
LEFT JOIN group_members AS m USING(group_id)
GROUP BY g.group_id
HAVING members > 4
example when references have different names
SELECT g.id, COUNT(m.member_id) AS members
FROM groups AS g
LEFT JOIN group_members AS m ON g.id = m.group_id
GROUP BY g.id
HAVING members > 4
Also, make sure that you set indexes inside your database schema for keys you are using in JOINS as it can affect your site performance.
SELECT DISTINCT groups.id,
(SELECT COUNT(*) FROM group_members
WHERE member_id = groups.id) AS memberCount
FROM groups
Your groups_main table has a key column named id. I believe you can only use the USING syntax for the join if the groups_fans table has a key column with the same name, which it probably does not. So instead, try this:
LEFT JOIN groups_fans AS m ON m.group_id = g.id
Or replace group_id with whatever the appropriate column name is in the groups_fans table.
Maybe I am off the mark here and not understanding the OP but why are you joining tables?
If you have a table with members and this table has a column named "group_id", you can just run a query on the members table to get a count of the members grouped by the group_id.
SELECT group_id, COUNT(*) as membercount
FROM members
GROUP BY group_id
HAVING membercount > 4
This should have the least overhead simply because you are avoiding a join but should still give you what you wanted.
If you want the group details and description etc, then add a join from the members table back to the groups table to retrieve the name would give you the quickest result.