Join username of sender and receiver with message info - mysql

I made a small user/messaging script as a learning exercise in PHP/MySQL. When I do the query to show the message, I would also like to output the user_username from the sender and the receiver. This is what I have so far:
SELECT
messages.*,
user_receiver.user_username as message_receiver_username,
user_sender.user_username as message_sender_username
FROM
messages
INNER JOIN
users user_receiver ON messages.message_receiver = user_receiver.user_id
INNER JOIN
users user_sender ON messages.message_sender = user_sender.user_id
Code on SQL Fiddle: http://sqlfiddle.com/#!9/5686aa/6
The problem is that this SQL code returns the usernames as "user_username" twice. I want to return the usernames as "message_receiver_username" and "message_sender_username".
New info: it seems the query works correct in phpMyAdmin, and it is SQL Fiddle that returns the original users table headers (user_username) instead of message_sender_username and message_receiver_username. Am I doing something wrong that makes the outcome different on different systems? Or is the query correct and SQL Fiddle wrong?
Here is some example content in the database, just to give you a better idea:
|-------------------------------|
| users |
|-------------------------------|
| user_id | user_username | ... |
|---------|---------------|-----|
| 1 | Max | |
| 2 | Maxim | |
| 3 | Maxim2 | |
| ... | ... | |
|-------------------------------|
|-------------------------------------------------------------|
| messages |
|-------------------------------------------------------------|
| message_id | ... | message_sender | message_receiver |...|
|-------------|-----|-----------------|-------------------|---|
| 1 | | 1 | 2 | |
| 2 | | 1 | 2 | |
| 3 | | 2 | 3 | |
| ... | | ... | ... | |
|-------------------------------------------------------------|

You should Write
SELECT
messages.*,
user_receiver.user_username as 'message_receiver_username',
user_sender.user_username as 'message_sender_username'
FROM
messages
INNER JOIN
users user_receiver ON messages.message_receiver = user_receiver.user_id
INNER JOIN
users user_sender ON messages.message_sender = user_sender.user_id
This will solve your problem

Related

Is it possible to use two COUNT and two JOIN in a SQL query from 3 tables?

So what I'm trying to do here is get a report on how many emails (with a MailChimp like app) were sent by different users, but I want two different metrics in one query. I want to know how many individual emails were sent by each user. Meaning if they sent 3 emails to 100 contacts each, that would display 300. But I also want to know how many unique emails were sent, meaning that would display 3.
I'd like to get something that looks like:
-------------------------------------------------------------
| Full Name | Username | Total Sent | Unique Mails |
|-------------|-----------------|------------|--------------|
| John Doe | jdoe#mail.com | 12000 | 4 |
| James Smith | jsmith#mail.com | 6000 | 12 |
| Jane Jones | jjones#mail.com | 4000 | 2 |
| ... | ... | ... | ... |
-------------------------------------------------------------
So I could know that John sends a few emails to a lot of contacts while James sends more emails to fewer contacts.
Here's what my query looks like. I've changed the table and column names, but this is otherwise an exact representation of what it is.
SELECT
CONCAT(Usernames.FirstName, ' ', Usernames.LastName) AS 'Full Name',
Usernames.Username,
COUNT(Sent_Mail_Contacts.IDContact) AS `Total Sent`,
COUNT(Mass_Mail.IDMass_Mail) AS `Individual E-Mails`
FROM Usernames
LEFT JOIN Sent_Mail_Contacts ON Usernames.Username = Sent_Mail_Contacts.Username
LEFT JOIN Mass_Mail ON Usernames.Username = Mass_Mail.Username
GROUP BY Usernames.Username
ORDER BY `Total Sent`
I have a table with Usernames, a table with individual contacts reached by which emails and a table with unique emails.
So does my query make sense or not? Is this even possible? Because right now when I run it, it gives me something like this:
-------------------------------------------------------------
| Full Name | Username | Total Sent | Unique Mails |
|-------------|-----------------|------------|--------------|
| John Doe | jdoe#mail.com | 12000 | 12000 |
| James Smith | jsmith#mail.com | 6000 | 6000 |
| Jane Jones | jjones#mail.com | 4000 | 4000 |
| ... | ... | ... | ... |
-------------------------------------------------------------
I just gives me the same number in both columns and takes 7 minutes to process.
Here is an example of what the 3 tables would look like separately if that can help:
Usernames
------------------------------------------------
| Username | FirstName | LastName | ... |
|-----------------|-----------|----------|-----|
| jdoe#mail.com | John | Doe | ... |
| jsmith#mail.com | James | Smith | ... |
| jjones#mail.com | Jane | Jones | ... |
| ... | ... | ... | ... |
------------------------------------------------
Mass_Mail
----------------------------------------------------
| ID_Mass_Mail | Username | Date | ... |
|--------------|----------------|------------|-----|
| 1 | jdoe#mail.com | 2019-01-16 | ... |
| 2 | jdoe#mail.com | 2019-01-29 | ... |
| 3 | jjones#mail.com| 2019-02-14 | ... |
| ... | ... | ... | ... |
----------------------------------------------------
Sent_Mail_Contacts
---------------------------------------------------------------------
| ID_Mass_Mail | Username | Contact_ID | Contact_Email | ... |
|--------------|----------------|------------|----------------|------
| 1 | jdoe#mail.com | 1 | bob#mail.com | ... |
| 1 | jdoe#mail.com | 2 | jim#mail.com | ... |
| 1 | jdoe#mail.com | 3 | cindy#mail.com | ... |
| ... | ... | ... | ... | ... |
| 2 | jdoe#mail.com | 4 | mike#mail.com | ... |
| 2 | jdoe#mail.com | 2 | jim#mail.com | ... |
| 2 | jdoe#mail.com | 3 | cindy#mail.com | ... |
| ... | ... | ... | ... | ... |
---------------------------------------------------------------------
Use COUNT(DISTINCT ...) :
SELECT
CONCAT(Usernames.FirstName, ' ', Usernames.LastName) AS 'Full Name',
Usernames.Username,
COUNT(Sent_Mail_Contacts.IDContact) AS `Total Sent`,
COUNT(DISTINCT Mass_Mail.IDMass_Mail) AS `Individual E-Mails`
FROM Usernames
LEFT JOIN Sent_Mail_Contacts ON Usernames.Username = Sent_Mail_Contacts.Username
LEFT JOIN Mass_Mail ON Usernames.Username = Mass_Mail.Username
GROUP BY Usernames.Username
ORDER BY `Total Sent`
NB : this will not make the query any faster though. To start with, you should at least make sure that you are using primary/foreign keys relations in the JOINs : Usernames(Username), Sent_Mail_Contacts(Username), Mass_Mail(Username)
Assuming the values in IDMass_Mail indicate a unique email, then you just need to edit the last COUNT to use the DISTINCT keyword.
COUNT(DISTINCT Mass_Mail.IDMass_Mail) AS `Individual E-Mails`
That will return the number of unique values in the grouping by Username.
You should also get a performance boost if you're able to add indexes to the Username columns in the Sent_Mail_Contacts and Mass_Mail tables.
I managed to do it using a query that (besides from changing the actual table and column names due to privacy concerns) looked exactly like this.
SELECT
Accounts.Account_Name AS `account`,
Usernames.Username AS `username`,
COUNT(Mass_Mail_Reached_Contacts.ID_Contact) AS `total_emails`,
COUNT(Mass_Mail_Reached_Contacts.ID_Mass_Mail) /
(
SELECT COUNT(*)
FROM
Mass_Mail_Reached_Contacts
WHERE
Mass_Mail_Reached_Contacts.DATE >= '2019-02-01'
AND
Mass_Mail_Reached_Contacts.DATE <= '2019-02-28'
)
* 100 AS `%`,
COUNT(DISTINCT Mass_Mail.ID_Mass_Mail) AS `unique_emails`,
COUNT(Mass_Mail_Reached_Contacts.ID_Mass_Mail) /
COUNT(DISTINCT mass_mail.ID_Mass_Mail)
AS `avg_contacts_per_email`
FROM
Usernames
LEFT JOIN Mass_Mail_Reached_Contacts ON Mass_Mail_Reached_Contacts.Username = Usernames.Username
LEFT JOIN Account ON Account.ID_Account = Usernames.ID_Account
LEFT JOIN Mass_Mail ON Mass_Mail.ID_Mass_Mail = Mass_Mail_Reached_Contacts.ID_mass_mail
WHERE
Mass_Mail_Reached_Contacts.DATE >= '2019-02-01'
AND
Mass_Mail_Reached_Contacts.DATE <= '2019-02-28'
GROUP BY
Usernames.Username
HAVING COUNT(DISTINCT Mass_Mail.IDMass_Mail) > 0
ORDER BY
`total_emails` DESC
I'm now able to get a table that looks like this
Emails Stats
--------------------------------------------------------------------------------------
| account | username | total_emails | % | unique_emails | avg_contact_email |
|----------|--------------|--------------|-------|------------------------------------
| Bob inc. | bob#mail.com | 28,550 | 14.52 | 12 | 2379.17 |
| ... | ... | ... | ... | ... | ... |
--------------------------------------------------------------------------------------
To start with: Why do Mass_Mail and Sent_Mail_Contacts both contain a Username? This looks redundant. Or is Sent_Mail_Contacts.ID_Mass_Mail nullable?
For this query at least, I suppose we can ignore the Username in Sent_Mail_Contacts completely. What really links the two tables is the ID_Mass_Mail, and you have forgotten this join criteria in your query.
select
ws_concat(' ', u.firstname, u.lastname) as full_name,
u.username,
count(smc.idmass_mail) as total_sent,
count(mm.idmass_mail) as individual_e_mails
from usernames u
left join mass_mail mm on mm.username = u.username
left join sent_mail_contacts smc on smc.id_mass_mail = u.id_mass_mail
group by u.username
order by total_sent;

duplicate row in many to many relationship mysql

I have many to many relation problem in this scenario
Table : customer_master
+---------+-----------+
| cust_id | cust_code |
+---------+-----------+
| 1 | S00333 |
+---------+-----------+
Table : customer_supply_chain
+----------------+-----------+-------------------+
| supply_cust_id | cust_code | supplye_cust_code |
+----------------+-----------+-------------------+
| 1 | S00333 | HI00001 |
| 2 | S00333 | MA00010 |
+----------------+-----------+-------------------+
Table : customer_vehicle
+----------------+-----------+------------------+
| cust_vehicl_id | cust_code | vehicle_model_id |
+----------------+-----------+------------------+
| 1 | S00333 | 161 |
| 2 | S00333 | 162 |
+----------------+-----------+------------------+
Mysql Query is :
SELECT
cv.vehicle_model_id,
csc.supply_cust_code AS suppl_code
FROM customer_master cm
LEFT JOIN customer_supply_chain csc
ON csc.cust_code = cm.cust_code
LEFT JOIN customer_vehicle cv
ON cv.cust_code = cm.cust_code
WHERE cm.cust_code = 'S00333'
result of query
+------------------+------------------+
| vehicle_model_id | supply_cust_code |
+------------------+------------------+
| 161 | HI00001 |
| 162 | HI00001 |
| 161 | MA00010 |
| 162 | MA00010 |
+------------------+------------------+
our desire output is
+------------------+------------------+
| vehicle_model_id | supply_cust_code |
+------------------+------------------+
| 161 | HI00001 |
| 162 | MA00010 |
+------------------+------------------+
The problem is in every row is repeated by supply_cust_code and vehicle_model_id,
We try with distinct and group by and other fixes (show in stack overflow) but not work,
If we use group by so we can not get all data and we don'T want to use group_concat , we cant rectify the problem ,
We just try to make getting all row but not repeated
I don't know why you are getting those duplicates, because the sample data does not support it, but you can either try using SELECT DISTINCT:
SELECT DISTINCT cv.vehicle_model_id,
csc.supply_cust_code AS suppl_code
FROM ...
Or you can try grouping on the model ID and supply customer code:
SELECT cv.vehicle_model_id,
csc.supply_cust_code AS suppl_code
FROM customer_master cm
LEFT JOIN customer_supply_chain csc
ON csc.cust_code = cm.cust_code
LEFT JOIN customer_vehicle cv
ON cv.cust_code = cm.cust_code
WHERE cm.cust_code = 'S00333'
GROUP BY cv.vehicle_model_id,
csc.supply_cust_code

Join two table mysql query return all user list values?

Join two table MySQL query return all user list values.
Please correct this query or provide some query.
Table1 : users
+---------+------------+-----------+
| user_id | user_name | cource_id |
+---------+------------+-----------+
| 1 | ramalingam | 1,2,3,4 |
| 2 | yuvi | 1 |
| 3 | Saravanan | 1,2,3 |
| 4 | gandhi | 1 |
+---------+------------+-----------+
Table2 : course
+-----------+-------------+
| cource_id | cource_name |
+-----------+-------------+
| 1 | php |
| 2 | wordpress |
| 3 | seo |
| 4 | magento |
+-----------+-------------+
Output
--------------------------------------
user_id | user_name | cource_id
--------------------------------------
1 | ramalingam| php,wordpress,seo,magnto
2 | yuvi | php
3 | Saravanan | php,wordpress,seo
4 | gandhi | php
This my query
SELECT u.user_id,u.user_name, GROUP_CONCAT(c.cource_name)as course_name
FROM users as u
LEFT JOIN course as c ON c.cource_id = u.user_id
Thank you for any help I can get on this...
In general DB design is bad, don't use comma separated lists at all. Hovewer you should use FIND_IN_SET() in your JOIN clause in order to achieve this:
SELECT
u.user_id,
u.user_name,
GROUP_CONCAT(c.cource_name) AS course_name
FROM
users AS u
LEFT JOIN cource AS c ON FIND_IN_SET(c.cource_id, u.cource_id)
GROUP BY
u.user_id,
u.user_name
Output is:
+---------+------------+---------------------------+
| user_id | user_name | course_name |
+---------+------------+---------------------------+
| 1 | ramalingam | php,wordpress,seo,magento |
| 2 | yuvi | php |
| 3 | Saravanan | php,wordpress,seo |
| 4 | gandhi | php |
+---------+------------+---------------------------+
4 rows in set

Converting sub-queries to joins

Given the following schema...
how would I go about converting the following query to use joins (to work with MySQL)?
SELECT submissions.SubmissionID,
(SELECT data.DataContent FROM data WHERE data.DataFieldName =
(SELECT forms.FormEmailFieldName FROM forms WHERE forms.FormID = submissions.SubmissionFormID)
AND data.DataSubmissionID = submissions.SubmissionID) AS EmailAddress,
(SELECT data.DataContent FROM data WHERE data.DataFieldName =
(SELECT forms.FormNameFieldName FROM forms WHERE forms.FormID = submissions.SubmissionFormID)
AND data.DataSubmissionID = submissions.SubmissionID) AS UserName
FROM submissions
WHERE submissions.SubmissionFormID = 4
Below is some sample data and my desired result...
+--------+--------------------+-------------------+
| forms | | |
+--------+--------------------+-------------------+
| FormID | FormEmailFieldName | FormNameFieldName |
| 4 | UserEmailAddress | UserName |
| 5 | email | name |
+--------+--------------------+-------------------+
+--------------+------------------+
| submissions | |
+--------------+------------------+
| SubmissionID | SubmissionFormID |
| 10 | 4 |
| 11 | 5 |
| 12 | 5 |
+--------------+------------------+
+--------+------------------+------------------+------------------+
| data | | | |
+--------+------------------+------------------+------------------+
| DataID | DataSubmissionID | DataFieldName | DataContent |
| 1 | 10 | UserEmailAddress | user#example.com |
| 2 | 10 | UserName | Paul D'Otherone |
| 3 | 11 | email | bob#bobs.com |
| 4 | 11 | name | Bob Bobbington |
| 5 | 11 | phone | 01234 5678910 |
| 6 | 11 | country | UK |
| 7 | 12 | name | Sheila Sausages |
| 8 | 12 | country | UK |
+--------+------------------+------------------+------------------+
+--------------------------+------------------+-----------------+
| DESIRED RESULT | | |
+--------------------------+------------------+-----------------+
| submissions.SubmissionID | EmailAddress | UserName |
| 10 | user#example.com | Paul D'Otherone |
| 11 | bob#bobs.com | Bob Bobbington |
| 12 | NULL | Sheila Sausages |
+--------------------------+------------------+-----------------+
Also see http://sqlfiddle.com/#!2/78dea/1/0
I've tried various combinations of inner joins and left joins but can't get a result set in the same format as the above query. I am still learning how to use joins and am finding this hard to get my head around.
You can do this with one join to forms and two to data, one for each field.
SELECT s.SubmissionID, de.DataContent as EmailAddress,
dn.DataContent as UserName
FROM submissions s LEFT JOIN
forms f
ON f.FormId = s.SubmissionFormID LEFT JOIN
data dn
ON d.DataFieldName = f.FormNameFieldName LEFT JOIN
data de
ON d.DataFieldName = f.FormEmailFieldName
WHERE s.SubmissionFormID = 4
In case there is missing data, then you want to use LEFT JOIN. This will ensure that you get all the rows (which your original query does).
I also added table aliases into the query. These make queries easier to write and to read.
Without having sample data, just a quick try:
SELECT
s.SubmissionID,
d1.DataContent AS EmailAddress,
d2.DataContent AS Username
FROM submissions s
JOIN forms AS f1 ON (f1.FormID = s.SubmissionFormID)
JOIN data AS d1 ON (d1.DataFieldName = f1.FormEmailFieldName)
JOIN data AS d2 ON (d2.DataFieldName = f1.FormNameFieldName)
WHERE s.SubmissionFormID = 4
sql fiddle for it: http://sqlfiddle.com/#!2/9f917/1
Starting from Olli's and Gordon's suggestions I have come up with the following which gives the same result set as my original query...
SELECT
s.SubmissionID,
d1.DataContent AS EmailAddress,
d2.DataContent AS Username
FROM submissions s
INNER JOIN forms AS f1 ON (f1.FormID = s.SubmissionFormID)
LEFT JOIN data AS d1 ON (d1.DataFieldName = f1.FormEmailFieldName and d1.DataSubmissionID = s.SubmissionID)
LEFT JOIN data AS d2 ON (d2.DataFieldName = f1.FormNameFieldName and d2.DataSubmissionID = s.SubmissionID)
WHERE s.SubmissionFormID = 4
Does this seem like the correct way to go about achieving what I want?

Mysql: get result from 2 tables

I have 2 tables.
Phonebook:
_________________________________
| id | Photo | Name | Number |
|---------------------------------|
| 1 | abc.jpg | John | 123-45-67 |
|---------------------------------|
| 2 | def.jpg | Sam | 482-34-00 |
|_________________________________|
History:
____________________________________
| id | Name | Date | Type |
|------------------------------------|
| 24 | John | 17.03.2014 | Incoming |
|------------------------------------|
| 25 | Sam | 18.03.2014 | Incoming |
|------------------------------------|
| 26 | Sam | 19.03.2014 | Outgoing |
|____________________________________|
I need to get all columns from History table where id = $id (25 in my case) and get Image column from Phoneboock where History.Name = Phonebook.Name (Sam in my case). Below is the result that I want to get:
______________________________________________
| id | Name | Date | Type | Image |
|----------------------------------------------|
| 25 | Sam | 18.03.2014 | Incoming | def.jpg |
|______________________________________________|
It seems your problem is the SQL to get your data, so use this:
SELECT History.*, Phonebook.Photo
FROM History INNER JOIN Phonebook ON Phonebook.Name = History.Name
AND History.id = $id
You can use JOIN as follows:
SELECT * FROM History INNER JOIN Phonebook WHERE History.name = Phonebook.name
That will give you a join of all the rows. You can customize it more to get what you want. Look at JOIN here for more info
If you are looking for the SQL Select statement, it would look something like this:
SELECT HISTORY.*, PHONEBOOK.Photo FROM HISTORY, PHONEBOOK
WHERE HISTORY.Name = PHONEBOOK.Name AND HISTORY.id='25'