3 tables and 2 independent JOINs with CONCAT expressions - mysql

I have the following 3 tables with IDs
Table: users
user | name
1 | Joe
2 | John
Table: user_id1
user | id1
1 | 2
1 | 3
2 | 5
Table: user_id2
user | id2
1 | 3
1 | 4
I would like to get the following result for each user
name | ids 1 | ids 2
Joe | 2,3 | 3,4
John| 5 | NULL
I use this query:
SELECT
user.name,
GROUP_CONCAT(user_id1.id1) AS "ids1",
GROUP_CONCAT(user_id2.id2) AS "ids2"
FROM users
LEFT JOIN user_id1
ON user_id1.user=users.user
LEFT JOIN user_id2
ON user_id2.user=users.user
But I get this result:
name | ids1 | ids2
Joe | 2,2,3,3 | 3,4,3,4
John | 5 | NULL
What is wrong?
Thanks for your help

Using DISTINCT should solve it
SELECT
user.name,
GROUP_CONCAT(DISTINCT user_id1.id1) AS "ids1",
GROUP_CONCAT(DISTINCT user_id2.id2) AS "ids2"
FROM users
LEFT JOIN user_id1
ON user_id1.user=users.user
LEFT JOIN user_id2
ON user_id2.user=users.user

Related

replace the id with the username from an other table in a CROSS JOIN in MySQL

This question is regarding this one: Joining multiple tables to get NOT EQUAL values in MySQL
I want to extend the following query:
SELECT
d.dataid,
d.colors,
u.userid,
u.username
FROM
users u
CROSS JOIN
datas d
WHERE
(u.userid , d.dataid) NOT IN (SELECT
c.userid, c.dataid
FROM
collections c)
AND u.userid = 1
For this data sample:
table datas table users table collections
dataid | colors | addedby userid | username collectionid | userid | dataid
-------------------------- ------------------- ------------------------------
1 | blue | 1 1 | Brian 1 | 1 | 1
2 | red | 1 2 | Jason 2 | 2 | 3
3 | green | 2 3 | Marie 3 | 1 | 3
4 | yellow | 3 4 | 3 | 2
These results are expected:
for Brian
dataid | colors | userid | username
-----------------------------------
2 | red | 1 | Brian
4 | yellow | 1 | Marie
for Jason
dataid | colors | userid | username
-----------------------------------
1 | blue | 2 | Brian
2 | red | 2 | Brian
4 | yellow | 2 | Marie
The row "addedby", which inherits the userid from users, has been added.
At the moment my query replaces the userid from users instead of the addedby from datas with the username.
I really need the userid from datas replaced, not the userid from users. :-)
Does anyone have a clue how to solve this?
Thanks in advance!
cheers
Just join users table once again with datas table. And in the output use username from this join.
SELECT
d.dataid,
d.colors,
uo.userid,
uo.username
FROM
users u
CROSS JOIN
datas d
INNER JOIN
users uo
ON d.added_by = uo.id
WHERE
(u.userid , d.dataid) NOT IN (SELECT
c.userid, c.dataid
FROM
collections c)
AND u.userid = 1
And I believe, that you might even write your query in this way
SELECT u.userid, u.username, d.dataid, d.colors
FROM username u
INNER JOIN datas d
ON u.userid = d.addedby
WHERE d.dataid NOT IN (
SELECT dataid
FROM collections
WHERE userid = 1
)

mySQL JOIN of several tables

I do have the following three tables in a MySQL-DB (InnoDB)
UserTab
ID | Name | ---
------------------
1 | Tom |
2 | Dick |
3 | Harry |
EventTab
ID | Name | ---
------------------
1 | Easter |
2 | Holidays |
3 | ThxGiving |
4 | Christmas |
ParticipationTab
ID | UserID | EventID
---------------------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 1
5 | 2 | 4
6 | 3 | 3
And I want to achieve the follwing result with my query:
QueryResultTab
UserTab.Name | EventTab.Name | NoPart | Names
-----------------------------------------------
Tom | Easter | 2 | Tom, Dick
Tom | Holidays | 1 | Tom
Tom | ThxGiving | 2 | Tom, Harry
Dick | Easter | 2 | Tom, Dick
Dick | Christmas | 1 | Dick
Harry | ThxGiving | 2 | Tom, Harry
I do know about Count() combined with GROUP to get the number of participants
I know about group-concat to get the "Names".
SELECT Event, GROUP_CONCAT(Name ORDER BY Name ASC SEPARATOR ', ') as Names
FROM
(SELECT ID as UserID, Name FROM X_Users WHERE ConditionA) AS UserTab
INNER JOIN
(SELECT EventID, UserID FROM X_Participation WHERE ConditionB) AS ParticipationTab
ON UserTab.UserID = ParticipationTab.UserID
INNER JOIN
(SELECT ID as EventID, Event FROM X_Events WHERE ConditionC) AS EventTab
ON ParticipationTab.EventID = EventTab.EventID
GROUP BY EventTab.EventID
This gives me:
ConcatTab
EventTab.Name | Names
---------------------------
Easter | Tom, Dick
Holidays | Tom
ThxGiving | Tom, Harry
Easter | Tom, Dick
Christmas | Dick
ThxGiving | Tom, Harry
I know about JOINs as you can see. Probably I could use LEFT or RIGHT JOINs as well for this.
For the other parts I use this query:
SELECT Name, Event, NoPart
FROM (SELECT ID as UserID, Name FROM X_Users WHERE ConditionA) AS UserTab
INNER JOIN (SELECT EventID, UserID FROM X_Participation WHERE ConditionB) AS PartTab
ON UserTab.UserID = PartTab.UserID
INNER JOIN (SELECT ID as EventID, Event FROM X_Events WHERE ConditionC) AS EvTab
ON PartTab.EventID = EvTab.EventID
INNER JOIN (SELECT EventID as CntID, COUNT(*) AS NoPart FROM X_Participation WHERE ConditionB) AS CntTab
ON EvTab.EventID = CntTab.CntID
ORDER BY UserTab.UserID
This gives me:
CountTab
UserTab.Name | EventTab.Name | NoPart
--------------------------------------
Tom | Easter | 2
Tom | Holidays | 1
Tom | ThxGiving | 2
Dick | Easter | 2
Dick | Christmas | 1
Harry | ThxGiving | 2
But how to combine/merge ConcatTab and CountTab into QueryResultTab? I want to retrieve the result table in PHP row by row with mysql_fetch_assco().
Please don't tell me about PDO, etc. I know about it.
The other option - what I try to avoid - is do it within a PHP-loop and use numerous tiny SQL-queries to achieve the result.
Based on your sample data, you want all the rows in the participation table, with information from the dimensions. Then you want a summary of that table.
Here is an approach that uses a subquery in the FROM clause:
SELECT u.name, e.name, p2.numPart, p2.Names
FROM X_Participation p INNER JOIN
X_Users u
ON u.UserID = p.UserID INNER JOIN
X_Events e
ON p.EventID = e.EventID INNER JOIN
(SELECT p2.EventId, COUNT(*) as numPart,
GROUP_CONCAT(u2.name SEPARATOR ', ') as names
FROM X_Participation p2 INNER JOIN
X_Users u2
ON u2.UserID = p2.UserID
GROUP BY p2.EventId
) p2
ON p2.EventId = p.EventId;
Notes:
If you are going to use table aliases (which you should), make them shorter, not longer than the table names.
Don't use subqueries unnecessarily. This is especially true in MySQL which materializes subqueries.
You can put additional conditions in a WHERE clause of the outer query.

How to get the count of voters who don't vote on a specific poll

I was able to get the total votes on my polls. But I need to get the total count where the voters didn't vote. For example voter#1 voted on president category and senator category only and voter#2 voted on vice pres and senator only. And last, voter#3 doesn't vote which i still put voter#3 on the poll votes and leave it NULL. So result should be
NUMBERS OF VOTERS WHO DIDN'T VOTE ON A SPECIFIC CATEGORY.
PRESIDENT : 2
VICE PRESIDENT : 2
SENATORS : 1
Where in voter#1 didn't vote for vp, voter#2 didn't vote for pres and voter#3 sent an empty votes.
Here are my tables.
Polls
id | poll_title
1 | presidential election
Poll_categories
id | poll_id | category_name
1 | 1 | President
2 | 2 | Vice-President
3 | 3 | Senator
Poll_items
id | poll_category_id | item_name
1 | 1 | Obama
2 | 1 | Bush
3 | 1 | Clinton
4 | 2 | Biden
5 | 3 | Shelby
6 | 3 | Murkowski
Poll_votes
id | voters_id | poll_item_id
1 | 1 | 1
2 | 1 | 5
3 | 1 | 6
4 | 2 | 4
5 | 2 | 6
6 | 3 | NULL
So far here is my query, but i don't know what to do next. I also can't show the voters_id 3 because it is NULL
select c.id, c.category_name, v.voters_id from poll_category c
LEFT JOIN (select v.user_id, v.poll_item_id, i.poll_category_id as cat_id, i.item_name
from poll_votes v
LEFT JOIN poll_items i on i.id = v.poll_item_id) v
ON v.cat_id = c.id
WHERE c.poll_id = 1
You can use the following query:
SELECT pc.id, COUNT(*)
FROM Poll_categories AS pc
CROSS JOIN (
SELECT DISTINCT voters_id
FROM Poll_votes) AS voters
LEFT JOIN (
SELECT voters_id, poll_category_id
FROM Poll_votes AS pv
LEFT JOIN Poll_items AS pi ON pv.poll_item_id = pi.id
) AS voters_cat
ON pc.id = voters_cat.poll_category_id AND voters.voters_id = voters_cat.voters_id
WHERE voters_cat.poll_category_id IS NULL
GROUP BY id
Demo here

Mysql data from table with condition

I have two mysql tables as follows:
contacts
---------------
id | name | email
---------------
1 | Jack | jack#test.com
2 | John | john#test.com
3 | Liz | liz#test.com
5 | Jack | jack#test.com
6 | Liz | liz#test.com
7 | Mike | mike#test.com
8 | Jack | jack#test.com
purchases
-------------------
id | contact_id | paid
-------------------
1 | 3 | true
2 | 5 | true
I need unique contact_ids that made purchase and other unique contact_ids that don't have made purchases.
So the final result will be as:
-------------------
id | name | email
------------------
2 | John | john#test.com
3 | Liz | liz#test.com
5 | Jack | jack#test.com
7 | Mike | mike#test.com
I tried the query as:
SELECT * FROM contacts LEFT JOIN purchases ON contacts.id = purchases.user_id
But this is not giving me unique rows as required. I tried several combination of DISTINCT, but I am not getting the result as required.
did you try this?
SELECT COALESCE(purchases.contact_id, contacts.id) as id, name, email
FROM contacts
LEFT JOIN purchases ON contacts.id = purchases.user_id
GROUP BY name
SQL FIDDLE
Something like that should work, but its performance is "?".
SELECT * FROM contacts WHERE id IN (
SELECT DISTINCT id as i FROM purchases
UNION
SELECT DISTINCT contact_id as i FROM purchases
)
GROUP BY id

How do I put a conditioned count of a joined table in a separate column of the same joined table

Lets say, I have two tables - people and bonus
------------
people
------------
people_id | company_id | job_id
1 | 1 | 2
2 | 1 | 4
3 | 2 | 1
4 | 2 | 3
5 | 3 | 5
------------
bonus
------------
job_id | bonus_id
1 | 101
2 | 102
3 | 103
Now, I want to have a joined table like the following
-------------
JOINED TABLE
-------------
people_id | company_id | job_id | bonus_id | no_of_bonus_for_company
1 | 1 | 2 | 102 | 1
2 | 1 | 4 | NULL | 1
3 | 2 | 1 | 101 | 2
4 | 2 | 3 | 103 | 2
5 | 3 | 5 | NULL | 0
I need to have the main search term in people_id as in -
SELECT p.people_id,
p.company_id,
p.job_id,
b.bonus_id
FROM people p
LEFT JOIN bonus b
ON p.job_id = b.job_id
WHERE p.people_id IN (1,2,3,4,5)
ORDER BY p.people_id ASC;
But how do I get the fifth column of the joined table? It actually counts the no. of bonus id's for each company id in the joined table itself.
I can only assume that you are telling us part of the picture so I will reserve judgement about the DB schema, normalization etc.
Given the presented facts you can retrieve the information in the following manner.
NOTE : This is TSQL syntax but I don't think that the mySQL syntax should be very different i.e. ISNULL -> IFNULL
SELECT p.people_id
, p.company_id
, p.job_id
, b.bonus_id
, ISNULL((
SELECT COUNT(pt.Job_Id)
FROM Bonus bt
INNER JOIN People pt
ON pt.job_Id = bt.job_Id
WHERE pt.company_Id = p.company_Id
GROUP BY pt.company_Id
), 0) AS no_of_bonus_for_company
FROM People p
LEFT JOIN Bonus b
ON p.job_Id = b.job_Id