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?
Related
I have 2 table in the database and ı am trying to filter some users according to some criterias.
criterias table
+---------+----------------------+--------------------+----------------------+
| user_id | searching_friendship | searching_practice | conversation_subject |
+---------+----------------------+--------------------+----------------------+
| 31 | | | science |
| 26 | on | on | love |
| 32 | on | off | science |
| 34 | | | |
+---------+----------------------+--------------------+----------------------+
user table
+---------+------------+-----------------------------+---------------+-------------+---------------+--------------+------------------+
| user_id | user_name | user_email | user_password | user_gender | user_language | language_lvl | last_login |
+---------+------------+-----------------------------+---------------+-------------+---------------+--------------+------------------+
| 26 | Furkan | furkanakgun#windowslive.com | 123 | | Türkiye | basic | 16.06.2019 11:57 |
| 31 | sfsdf | asdfasdf#hotmail.com | 123 | Male | Afrikaans | basic | 09.06.2019 20:01 |
| 32 | denemeuser | xxx#hotmail.com | 123 | Male | Amharic | intermediate | 16.06.2019 11:57 |
| 33 | Smith | ssdf | 123 | male | ing | upper | NULL |
| 34 | luser | llll#hotmai.com | 123456 | Male | Afrikaans | basic | 16.06.2019 10:32 |
+---------+------------+-----------------------------+---------------+-------------+---------------+--------------+------------------+
I am trying to match users who have same criterias.What i do is
$userId=$_SESSION['userId'];
$sql="SELECT* FROM criterias WHERE user_id='$userId'";
$query=mysqli_query($conn,$sql);
while($result=mysqli_fetch_assoc($query)){
$friendshipCheck=$result['searching_friendship'];
$pracCheck=$result['searching_practice'];
$conversationSub=$result['conversation_subject'];
}
so I am getting current criterias informations and ı am trying to match with other users like this
SELECT* FROM users,criterias WHERE (users.user_id=criterias.user_id AND users.user_id!='$userId') AND criterias.searching_friendship='$friendshipCheck' OR criterias.searching_practice='$pracCheck'
But it doesnt work. Do you have any idea how to fix this dear friends ?
If you want to get only the users with the same criteria as yours this query should work
SELECT *
FROM users AS u
INNER JOIN criterias AS c ON u.user_id = c.user_id
WHERE u.user_id != '$userId'
AND c.searching_friendship = '$friendshipCheck'
AND c.searching_practice = '$pracCheck'
AND c.conversation_subject = '$conversation_subject'
Providing the expected results vs what you are getting would help proving the best solution.
Here, I am trying to write the query based on the understanding of what you have tried to write in your code:
;WITH CTE AS
(
SELECT C.*
FROM Criterias C
WHERE C.user_id = <user_id_input>
)
SELECT *
FROM User U
INNER JOIN Criterias C
ON U.user_id = C.user_id
WHERE EXISTS (
SELECT 1
FROM CTE
WHERE CTE.searching_friendship = C.searching_friendship
OR CTE.searching_practice = C.searching_practice
)
AND U.user_id != <input_user_id> ;
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
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
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'
Okay, so these are my three tables:
USER
|--------+----------+----------|
| UserID | UserName | IsActive |
|--------+----------+----------|
| 10 | Mike | 1 |
| 11 | John | 1 |
| 12 | Beth | 1 |
|--------+----------+----------|
REPORT_DISTRIB (Linking Table)
|-----------+--------+----------+---------------|
| DistribID | UserID | ReportID | DistribToUser |
|-----------+--------+----------+---------------|
| 1 | 10 | 50 | 1 |
| 2 | 12 | 52 | 0 |
| 3 | 14 | 54 | 1 |
|-----------+--------+----------+---------------|
REPORT
|----------+------------+---------------|
| ReportID | ReportName | Distributable |
|----------+------------+---------------|
| 50 | FY2010 | 1 |
| 51 | FY2011 | 1 |
| 52 | FY2012 | 1 |
|----------+------------+---------------|
In the problem I'm facing, I have 200 users from the USER table that are active and 10 reports from the REPORT table that are distributable. For every user I need to display the User Name, the Report Name, and whether that report should be distributed to the user, like so:
|----------+------------+---------------|
| UserName | ReportName | DistribToUser |
|----------+------------+---------------|
| Mike | FY2010 | 1 |
| Beth | FY2012 | 0 |
|----------+------------+---------------|
What I'm trying to achieve is a list of 2000 results (200 users x 10 reports). The problem is that the REPORT_DISTRIB linking table doesn't have a record for every user with each report. I still feel like this should be possible... am I wrong in my thinking? Any help is greatly appreciated.
It's rough, but this is my query so far (which returns 1790 results):
SELECT u.UserName, r.ReportName, rd.DistribToUser
FROM USER u
LEFT JOIN REPORT_DISTRIB rd on rd.UserID = u.UserID
and rd.ReportID in (select r.ReportID from REPORT r where r.Distributable = 1)
OUTER APPLY (select r.ReportName from REPORT r where r.ReportID = rd.ReportID) r
WHERE u.IsActive = 1
SELECT u.UserName, r.ReportName, COALESCE(rd.DistribToUser, 0)
FROM USER u
CROSS JOIN REPORT r
LEFT JOIN REPORT_DISTRIB rd
ON u.UserID = rd.UserID
AND r.ReportID = rd.ReportID
WHERE u.IsActive = 1
AND r.Distributable = 1