I've got two tables, in which both id_health_center and id_user are used as composite key:
health_center_review
id_health_center
id_user
review
health_center_grade
id_health_center
id_user
grade_service
I would like to build a query that would return reviews from health_center_review with grades given by the same user. For example:
id_health_center | id_user | review
---------------------------------------
1 | 1 | something 1
1 | 2 | something 2
id_health_center | id_user | grade_service
-------------------------------------------
1 | 1 | 5
would return:
id_user | review | grade_service
----------------------------------------------------
1 | something 1 | 5
2 | something 2 | NULL
I have tried the following query:
SELECT hcr.id_user, review, grade_service
FROM health_center_reviews hcr
LEFT JOIN health_center_grades hcg ON hcg.id_health_center = hcr.id_health_center AND hcg.id_user = hcr.id_user
WHERE hcr.id_health_center = 1;
hovewer that only returns reviews if they have grades. If I omit the user part in join clause, it returns the grade for other user.
Related
I have this query:
INSERT INTO Votes (id_post,id_user)
SELECT ?,?
FROM Posts p, Users u
WHERE p.id_user = :id_author
AND u.id = $_SESSION['id']
AND u.active = 1
limit 1;
Now I want to use JOIN instead of ,. But there isn't any common column between those two tables. So what should I write in ON clause?
What I'm trying to do:
I have three tables:
// Posts
+----+----------+---------------+-----------+
| id | title | content | id_author |
+----+----------+---------------+-----------+
| 1 | title1 | content1 | 1234 |
| 2 | title2 | content2 | 5678 |
+----+----------+---------------+-----------+
// ^ the id of post's author
// Users
+----+--------+--------+
| id | name | active |
+----+--------+--------+
| 1 | jack | 1 |
| 2 | peter | 0 |
| 3 | John | 1 |
+----+--------+--------+
// Votes
+----+---------+---------+
| id | id_post | id_user |
+----+---------+---------+
| 1 | 32 | 1234 |
| 2 | 634 | 5678 |
| 3 | 352 | 1234 |
+----+---------+---------+
// ^ the id of current user
Now I need to check two conditions before inserting a new vote into Votes table:
Is the id of author the same as what I pass as id_author? Posts.id_user = :id_author (I know I can do that by a FK, but I don't want)
The account of current user is active? Users.active = 1
Sum Up: I'm trying to don't let people be able to vote who are inactive (active = 0). For example if Stackoverflow bans you, then you cannot vote to posts anymore, because you (current user) are banned. So I'm pretty sure $_SESSION['id'] should be used in the query to determine current user.
I suggest using exists instead of join:
INSERT INTO Votes (id_post, id_user)
SELECT id_post, id_user FROM (SELECT ? id_post, ? id_user) a
WHERE EXISTS (
SELECT 1 FROM Users
WHERE id = ?
AND active = 1
) AND EXISTS (
SELECT 1 FROM posts
WHERE id_user = :id_author
)
You already have a join here! This is an implicit join.
INNER JOIN and , (comma) are semantically equivalent in the absence of
a join condition: both produce a Cartesian product between the
specified tables (that is, each and every row in the first table is
joined to each and every row in the second table).
So there isn't a need for you to 'introduce' a join here.
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
Here is the sqlFiddle
I want to filter the users who have selected entities ,So if I want to filter user with entity say entity having ids "1" and "3" I hope to get the users which have both of these entities.
No of entities selected can vary in number .
Query I am using is
SELECT user_id from user_entities where entity_id IN(1,3)
but for obvious reason it is returing me result as
+----+-----------+---------+--------+
| ID | ENTITY_ID | USER_ID | STATUS |
+----+-----------+---------+--------+
| 1 | 1 | 3 | 1 |
| 2 | 3 | 3 | 1 |
| 7 | 1 | 2 | 1 |
| 29 | 3 | 1 | 1 |
+----+-----------+---------+--------+
So I will apply distinct to it it will give me user id with ids 1,2,3 but I only want user 3 as this is the only user having both entities .
What can be modified to get the exact results
You could join the table to itself specifying both IDs as part of the join condition:
SELECT e1.user_id
FROM user_entities e1
INNER JOIN user_entities e2
ON e1.user_id = e2.user_id AND
e1.entity_id = 1 AND
e2.entity_id = 3;
I'd like a little help here.
I'm building a database in MySQL where I will have a bunch of different activities. Each activity is part of a list.
So, I have the following tables on my database.
List
id
name
Activity
id
name
idList (FK to List)
I also want to know when each activity is finished (you can finish the same activity many times). To accomplish that, I have another table:
History
date
idActivity (FK to activity)
When the user finishes an activity, I add the id of this activity and the current time the activity was finished, to the History table.
I want to get the entire list with the date it was finished. When an activity has not been finished, I want it to show the date as null.
But, getting the list just once is easy. A simple Left Outer Join will do the trick. My issue here is that I want to get the ENTIRE list everytime a date appears on the history table.
This is what I'm looking for:
List:
id | name
1 | list1
Activity:
id | name | idList
1 | Activity1 | 1
2 | Activity2 | 1
3 | Activity3 | 1
4 | Activity4 | 1
5 | Activity5 | 1
6 | Activity6 | 1
History:
date | idActivity
17/07/14 | 1
17/07/14 | 3
17/07/14 | 4
17/07/14 | 6
16/07/14 | 2
16/07/14 | 3
16/07/14 | 5
Expected Result:
idActivity | idList | activityName | date
1 | 1 | Activity1 | 17/07/14
2 | 1 | Activity2 | NULL
3 | 1 | Activity3 | 17/07/14
4 | 1 | Activity4 | 17/07/14
5 | 1 | Activity5 | NULL
6 | 1 | Activity6 | 17/07/14
1 | 1 | Activity1 | NULL
2 | 1 | Activity2 | 16/07/14
3 | 1 | Activity3 | 16/07/14
4 | 1 | Activity4 | NULL
5 | 1 | Activity5 | 16/07/14
6 | 1 | Activity6 | NULL
The "trick" is to use a CROSS JOIN (or semi-cross join) operation with a distinct list of dates from the history table, to produce the set of rows you want to return.
Then a LEFT JOIN (outer join) to the history table to find the matching history rows.
Something like this:
SELECT a.id AS idActivity
, a.idList AS idList
, a.name AS activityName
, h.date AS `date`
FROM activity a
CROSS
JOIN ( SELECT s.date
FROM history s
GROUP BY s.date
) r
LEFT
JOIN history h
ON h.idActivity = a.id
AND h.date = r.date
ORDER
BY r.date
, a.id
That query gets the six rows from activity, and two rows (distinct values of date) from history (inline view aliased as r). The CROSS JOIN operation matches each of the six rows with each of the two rows, to produce a Cartesian product of 12 rows.
To get the rows returned in the specified order, we order by date, and then by activity.id.
I have the follow structure
user
id | name
----------
1 | Foo
2 | Bar
profile
id | name | user_id
--------------------------
1 | Profile 1 | 1
2 | Profile 2 | 2
profile_access
id | user_id | profile_id
--------------------------
1 | 2 | 1
Expect the follow result from a query
id | name | user_id
-----------------------------------
1 | Profile 1 | 1
2 | Profile 2 | 2
1 | Profile 1 | 2
But I do't know how to "merge" these tables. I tried:
SELECT profile.*
FROM profile profile
LEFT JOIN profile_access AS profile_access
ON (
profile_access.profile_id = profile.id
)
Which returns
id | name | user_id
-----------------------------------
1 | Profile 1 | 1
2 | Profile 2 | 2
And
SELECT profile.*
FROM profile profile
RIGHT JOIN profile_access AS profile_access
ON (
profile_access.profile_id = profile.id
)
Which results
id | name | user_id
-----------------------------------
2 | Profile 1 | 2
What is the correct way to do this query? Am I using joins wrong or expecting a impossible result with these tables?
EDIT:
Expected result should be:
id | name | user_id
-----------------------------------
1 | Profile 1 | 1
2 | Profile 2 | 2
1 | Profile 1 | 2
It is unclear what the exact logic you want is, but the following returns the results in the question:
select p.id, p.name, p.user_id
from profile p
union all
select p.id, p.name, pa.user_id
from profile p join
profile_access pa
on pa.profile_id = p.id;
EDIT:
This returns:
id | name | user_id
-----------------------------------
1 | Profile 1 | 1
2 | Profile 2 | 2
1 | Profile 1 | 2
Note that the last row has a 1 for the id instead of a 2 (as in the original expected answer). This is sensible to me, because id = 1 is only tied to profile name = 'Profile 1' in the table. But, to get the actual output:
select p.id, p.name, p.user_id
from profile p
union all
select pa.profile_id, p.name, pa.user_id
from profile p join
profile_access pa
on pa.user_id = p.user_id;
The reason I went with the first solution is because the sample queries all join profile and profile_access on the profile_id field and not on the user_id field.