I have two tables, users and survey. I want query the table user and to join the table survey in a way that only the survey record with the lowest value is returned for each record in user table.
I want to avoid subqueries and temporary tables.
table users:
--------------
| uid | name |
--------------
| 1 | mike |
| 2 | john |
| 3 | bill |
--------------
table survey:
----------------------
| id | uid | value |
----------------------
| 1 | 3 | 9 |
| 2 | 3 | 5 |
| 3 | 1 | 3 |
| 4 | 1 | 7 |
| 5 | 1 | 2 |
| 6 | 2 | 4 |
| 7 | 2 | 9 |
| 8 | 1 | 0 |
| 9 | 2 | 5 |
---------------------
expected output:
---------------------
| id | name | value |
---------------------
| 8 | mike | 0 |
| 2 | bill | 5 |
| 6 | john | 4 |
---------------------
What kind of JOIn should I do, or how should I write the query?
The following query gets all rows with minimum value (doesn't exist another survey with value under the selected value)
Try this:
SELECT u.*, s.value
FROM survey s
JOIN users u
ON s.uid = u.uid
WHERE NOT EXISTS(
SELECT 'maximum'
FROM survey s2
WHERE s2.uid = s.uid
AND s2.value < s.value)
You could use something like this:
select s.id, u.name, y.min_value
from
(
select uid, min(value) as min_value
from survey
group by uid
) y
join survey s
on s.value = y.min_value
and s.uid = y.uid
join user u
on u.uid = y.uid
I think this will help you
SELECT * FROM SURVEY S
INNER JOIN USERS U
ON S.UID=U.UID
QUALIFY ROW_NUMBER() OVER (PARTITION BY S.UID ORDER BY S.VALUE1 ASC )=1;
Related
Attempting to join two tables on user_id. The users table has unique id for each user. The user_codes table can have multiple rows with the same user_id. I only want to return 1 row from the joined user_codes table, where code_count is the largest.
users Table
| id | email |
| -------- | --------------- |
| 1 | user1#gmail.com |
| 2 | user2#gmail.com |
| 3 | user3#gmail.com |
user_code TABLE
| user_id | invite_code | count |
| -------- | ----------- | ------|
| 1 | X49MCL1 | 40 |
| 1 | K59CLT9 | 1000 |
| 2 | X5BC924 | 15 |
| 2 | 38DF80L | 8 |
| 3 | 641020T | 22 |
EXPECTED RESULT
| id | email | invite_code | count |
| --- | --------------- | ----------- | ------|
| 1 | user1#gmail.com | K59CLT9 | 1000 |
| 2 | user2#gmail.com | X5BC924 | 15 |
| 3 | user3#gmail.com | 641020T | 22 |
The query result only includes a single instance of each user found in the user_codes table with the highest count.
Here is the closest query I could get, but it only returns the invite_code and count for the first user.
SELECT a.id, a.email, b.invite_code, b.count
FROM users a
LEFT JOIN user_codes b
ON b.user_id = a.id
AND b.count = (SELECT MAX(count) FROM user_codes GROUP BY b.user_id)
The above query returns the result:
| id | email | invite_code | count |
| --- | --------------- | ----------- | ------ |
| 1 | user1#gmail.com | K59CLT9 | 1000 |
| 2 | user2#gmail.com | `NULL` | `NULL` |
| 3 | user3#gmail.com | `NULL` | `NULL` |
I can't seem to figure out how/why the records after the first one don't include the invite_code and the count.
Thanks for help!
On MySQL 8+, I suggest using the RANK() window function:
WITH cte AS (
SELECT u.id, u.email, uc.invite_code, uc.count,
RANK() OVER (PARTITION BY u.id ORDER BY uc.count DESC) rnk
FROM users u
INNER JOIN user_code uc
ON uc.user_id = u.id
)
SELECT id, email, invite_code, count
FROM cte
WHERE rnk = 1;
The RANK() function will also match multiple records per user tied for the highest count.
You might be able to salvage your current attempt by correlating the user inside the subquery to the outer query:
SELECT a.id, a.email, b.invite_code, b.count
FROM users a
LEFT JOIN user_codes b
ON b.user_id = a.id AND
b.count = (SELECT MAX(uc.count) FROM user_codes uc WHERE uc.user_id = a.id);
I have table with users:
+-----------+----------+
| id | name |
+-----------+----------+
| 1 | Joe |
| 2 | Tom |
| 3 | Jack |
| 4 | Tim |
+-----------+----------+
and second table with tasks liked with these users:
+--------------+--------------+--------------+
| id | user_id | status |
+--------------+--------------+--------------+
| 1 | 1 | new |
| 2 | 1 | done |
| 3 | 1 | in_progress |
| 4 | 2 | in_progress |
| 5 | 2 | done |
| 6 | 2 | done |
| 7 | 2 | done |
| 8 | 3 | new |
| 9 | 3 | new |
| 10 | 3 | new |
| 11 | 4 | in_progress |
| 12 | 4 | in_progress |
| 13 | 4 | new |
+--------------+--------------+--------------+
Each task could be in 'new', 'in_progress' or 'done' status.
I would like to get a list of user_ids who do not have any tasks in 'new' status but have a task in 'done' status.
Could anyone help me with this? Thanks in advance!
A variety of ways to accomplish this. Here are just a couple:
Query #1: Use CTEs
with done as (
select distinct user_id
from tasks
where status = 'done'
),
new as (
select distinct user_id
from tasks
where status = 'new'
)
select u.id, u.name
from users u
join done d
on u.id = d.user_id
where u.id not in (select user_id from new);
id
name
2
tom
Query #2: No CTEs
select id, name
from users
where id in (select user_id from tasks where status = 'done')
and id not in (select user_id from tasks where status = 'new');
id
name
2
tom
View on DB Fiddle
select u.id , u.name,t.status from users u
left join tasks t on t.user_id = u.id
where t.status<>'new';
so what I am trying to do is having 3 tables (pictures, collections, and bridge) with the following columns:
Collections Table:
| id | name |
------------------
| 1 | coll1 |
| 2 | coll2 |
------------------
Pictures Table: (timestamps are unix timestamps)
| id | name | timestamp |
-------------------------
| 5 | Pic5 | 1 |
| 6 | Pic6 | 19 |
| 7 | Pic7 | 3 |
| 8 | Pic8 | 892 |
| 9 | Pic9 | 4 |
-------------------------
Bridge Table:
| id | collection | picture |
-----------------------------
| 1 | 1 | 5 |
| 2 | 1 | 6 |
| 3 | 1 | 7 |
| 4 | 1 | 8 |
| 5 | 2 | 5 |
| 6 | 2 | 9 |
| 7 | 2 | 7 |
-----------------------------
And the result should look like this:
| collection_name | picture_count | newest_picture |
----------------------------------------------------
| coll1 | 4 | 8 |
| coll2 | 3 | 9 |
----------------------------------------------------
newest_picture should always be the picture with the heighest timestamp in that collection and I also want to sort the result by it. picture_count is obviously the count of picture in that collection.
Can this be done in a single statement with table joins and if yes:
how can I do this the best way?
A simple method uses correlated subqueries:
select c.*,
(select count(*)
from bridge b
where b.collection = c.id
) as pic_count,
(select p.id
from bridge b join
pictures p
on b.picture = b.id
where b.collection = c.id
order by p.timestamp desc
limit 1
) as most_recent_picture
from collections c;
A more common approach would use window functions:
select c.id, c.name, count(bp.collection), bp.most_recent_picture
from collections c left join
(select b.*,
first_value(p.id) over (partition by b.collection order by p.timestamp desc) as most_recent_picture
from bridge b join
pictures p
on b.picture = p.id
) bp
on bp.collection = c.id
group by c.id, c.name, bp.most_recent_picture;
I am having an issues with fetching a particular kind of record from the database.
I have three different tables
Friends
Followers
PictureGalleries
Here is a sample of what the table looks like
Friends:
|id | senderId | receiverId | accepted |
|---|----------| -----------| ---------|
| 1 | 1 | 12 | 1 |
| 2 | 12 | 2 | 1 |
| 2 | 12 | 2 | 1 |
Followers:
| id | userId | UserIsFollowing |
| -- | ------ | --------------- |
| 1 | 12 | 63 |
| 2 | 22 | 12 |
PictureGalleries:
| id | UserId |
| -- | ------ |
| 1 | 13 |
| 2 | 12 |
| 3 | 1 |
| 4 | 10 |
| 5 | 2 |
| 6 | 63 |
So now here is the Issue!
I want to select all from the Picture Galleries
Where the userid has a friendship relationship with userId 12 where accepted is 1
And
Where the userID 12 is following a particular user
So Basically the result I want to see is the picture gallery of the following users ID: 1,2, and 63 which will look like this:
| id | UserID |
| -- | ------ |
| 3 | 1 |
| 5 | 2 |
| 6 | 6 |
use union and sub-query to get desired result
select p.id,p.UserId from
( select UserIsFollowing as id from
Followers fl where userId =12
union select senderId from friends f
where f.receiverId =12 AND accepted=1
union select receiverId from friends f
where f.senderId =12 AND accepted=1
) as t join PictureGalleries p on t.id=p.UserId
I think this query shows what you want:
select * from PictureGalleries
join Followers on Followers.userId = PictureGalleries.UserId
where exists (select 1 from Friends where (Friends.senderId = PictureGalleries.UserId or Friends.receiverId = PictureGalleries.UserId) and accepted = 1)
and Followers.UserIsFollowing = :user_id
But I think your model can be improved
EDIT:
Maybe you said it wrong first when you've said:
"Where the userid has a friendship relationship with userId 12 where accepted is 1
AND Where the userID 12 is following a particular user"
I think you mean OR, so the SQL should be something like:
select * from PictureGalleries
where exists (select 1 from Friends where (Friends.senderId = PictureGalleries.UserId or Friends.receiverId = PictureGalleries.UserId) and accepted = 1)
OR exists (select 1 from Followers where Followers.userId = PictureGalleries.UserId and Followers.UserIsFollowing = :user_id
I have 3 tables:
Users
| id | name |
|----|-------|
| 1 | One |
| 2 | Two |
| 3 | Three |
Likes
| id | user_id | like |
|----|---------|-------|
| 1 | 1 | 3 |
| 2 | 1 | 5 |
| 3 | 2 | 1 |
| 4 | 3 | 2 |
Transations
| id | user_id | transaction |
|----|---------|-------------|
| 1 | 1 | -1 |
| 2 | 2 | 5 |
| 3 | 2 | -1 |
| 4 | 3 | 10 |
I need get sum of likes.like and transations.transation for each user and then sort it by its result.
I was able to do it for users and likes:
select users.*, sum(likes.like) as points
from `users`
inner join `likes` on `likes`.`user_id` = `users`.`id`
group by `users`.`id`
order by points desc
But then I add transactions table like this:
select users.*, (sum(likes.like)+sum(transactions.`transaction`)) as points
from `users`
inner join `likes` on `likes`.`user_id` = `users`.`id`
inner join `transactions` on `transactions`.`user_id` = `users`.`id`
group by `users`.`id`
order by points desc
It is show wrong results.
I expecting to see:
| id | name | points |
|----|-------|--------|
| 3 | Three | 12 |
| 1 | One | 7 |
| 2 | Two | 5 |
But get this instead:
| id | name | points |
|----|-------|--------|
| 3 | Three | 12 |
| 1 | One | 6 |
| 2 | Two | 5 |
So, how sort users by sum likes.like and transations.transation?
Thank you!
Since there's not a 1-to-1 relationships between transactions and likes, I think you need to use subqueries:
select users.*,
(select sum(points) from likes where user_id = users.id) as points,
(select sum(transaction) from transactions where user_id = users.id) as transactions
from users
order by points desc
Updated after more explanation of requirements:
select users.*,
(select sum(points) from likes where user_id = users.id) +
(select sum(transaction) from transactions where user_id = users.id) as points
from users
order by points desc