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.
Related
This is my table following now i want to find the list of follower of user 1 that are also followed by user 1
id | user | follower
-----------------------
1 | 1 | 2
2 | 2 | 1
3 | 1 | 3
4 | 3 | 1
For example i want to find the list of my followers who are also following me
With EXISTS:
select t.follower from tablename t
where
t.user = 1
and exists (
select 1 from tablename
where user = t.follower and follower = t.user
)
See the demo.
Results
| follower |
| -------- |
| 2 |
| 3 |
You could self-join the table:
SELECT f1.user
FROM followers f1
JOIN followers f2 ON f1.user = f2.follower AND f1.follower = f2.user
WHERE f1.follower = 1 -- For a specific user
I know that the question title may not be quit clear to understand but I try to explain:
users_table:
id | name | admin | property_id
-----------------------------------
1 | x | 1 | 0
2 | y | 1 | 0
3 | z | 0 | 1
5 | t | 0 | 2
6 | u | 0 | 2
7 | o | 0 | 2
users_table has two or more records which are admin and some other records which belong to one of these admin records by matching the property_id with the id. In the end what I want is the admin row data and the count of its properties. This is what should be the output from the first part of the query:
id | name | admin | property_count
-----------------------------------
1 | x | 1 | 1
2 | y | 1 | 3
Until now I know how to get the desired results but here begins the problem.I have another table
sells_table:
id | seller_id | sell_amount
----------------------------
1 | 3 | 250
2 | 5 | 120
3 | 7 | 100
4 | 5 | 200
So this is the logic: every admin has many properties and each property has many sells.
I want all records for each admin from the users_table plus the count of its property_id.
And then query the sells_table in a way where for each property of each admin the number of sells and the sum of the total sells gets calculated.
for example this should be the result for the admin with the id 2 and the name y:
name | properties | property_sells | property_amount
--------------------------------------------------------
y | 3 | 3 | 420
y has 3 properties. Property with id 5 which belongs to y(admin) has two sells and id 7 which also belongs to y(admin) has one sell and the sum of these 3 sells is 420.
I think this is what you want:
select ua.id, ua.name, ua.admin, count(distinct u.id) as property_count,
sum(s.sell_amount) as amount
from users_table ua left join
users_table u
on ua.id = u.property_id left join
sales s
on s.seller_id = u.id
where ua.admin = 1
group by ua.id, ua.name, ua.admin;
http://sqlfiddle.com/#!9/36834d/2
SELECT u.id, U.name, u.admin, COUNT(DISTINCT ut.id) property_count, SUM(st.sell_amount)
FROM users_table u
LEFT JOIN users_table ut
ON u.id = ut.property_id
LEFT JOIN sells_table st
ON ut.id = st.seller_id
WHERE u.admin = 1
GROUP BY u.id, u.admin, u.name
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
)
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've got the following two SQL tables (in MySQL):
Users
| id | name |
|----|------|
| 1 | Luke |
| 2 | Mark |
| 3 | Lucy |
| 4 | Biff |
User category
| user_id | category_id |
|---------|-------------|
| 1 | 5 |
| 1 | 6 |
| 2 | 5 |
| 2 | 7 |
| 3 | 5 |
I want users that are in User category but not if category id is 6.
In this case Mark and Lucy because Luke is in category 6 too and Biff has no category.
There is a way to do it without subquery and only in one query?
You can group by user_id and eliminate those rows where there is atleast one category_id of 6.
select uc.user_id,u.name
from user_category uc
join users u on uc.user_id = u.id
group by uc.user_id,u.name
having sum(case when category_id = 6 then 1 else 0 end) = 0
Join them and check for difference :
SELECT * FROM users
INNER JOIN user_category ON (user_category.user_id = users.id)
WHERE user_category.category_id <> 6
p.s. using group by is not effective, cuz it says to DB engine to do additional group by operation after gathering data.