简体   繁体   中英

Nested queries , subquery SQL

I have two tables:

select * from friends;
 user_id | friend_id |         created_at         
---------+-----------+----------------------------
 user    | user2     | 2017-01-09 21:29:56.31972
 user    | user3     | 2017-01-09 21:29:58.567925
 user    | user4     | 2017-01-09 21:30:01.200806
 user2   | user      | 2017-01-09 21:30:49.498912
 user3   | user      | 2017-01-09 21:30:53.549042
 user4   | user      | 2017-01-09 21:30:56.519135
    id | user_id | user_from | message 
----+---------+-----------+---------
  1 | user    | user2     | hey
  2 | user    | user3     | de
  3 | user    | user4     | bal
  4 | user    | user3     | ok
  5 | user    | user3     | nice
  6 | user    | user4     | cana
  7 | user    | user2     | doc

This SQL statement successfully retrieves the last message to one user. For example. The last message sent by user3 to user

select id, user_from, message 
from messages 
WHERE user_id = 'user' 
AND user_from = 'user3' 
ORDER BY id DESC 
limit 1;
 id | user_from | message 
----+---------+---------
  5 | user3    | nice

I need to retrieve a collection of messages. Each message represents the last message sent by a friend to an user

What I need is to combine a query so that I get something like this

id | user_from | message 
----+-----------+---------
  7 | user2     | doc
  5 | user3     | nice
  6 | user4     | cana

distinct on is the easiest solution here.

select DISTINCT ON(user_from) id, user_from, message 
from messages WHERE user_id = 'user'
ORDER BY user_from,id DESC;

This uses a postresql extension to the SQL standard, there's also a standard way to do this using window functions, but it's more complicated, and a potentially inefficient way using a self-join.

You can use join and window function (for your case is row_number ).

Assuming the first table is friends and the second one is messages , this solution might work (not tested yet).

select id, user_from, message
from (
  select m.*
    , row_number() over(partition by m.user_from order by f.created_at desc) as N
  from friends f, messages m
  where f.user_id = m.user_id and f.friend_id = m.user_from ) x
where N = 1;

Start by normalizing your database, relational databases need this.

Im not sure how familiar you are with db design and sql. But look into using joins, which work better with a normalized db ;)

Read up about normalization here http://www.studytonight.com/dbms/database-normalization.php

Also look up joins on w3schools or tutorialspoint, youll get what you need

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM