I have the following schema
Relationship:
fromId (fkey)
toId (fkey)
isFriend (boolean)
isBlocked (boolean)
A user requests friendship by adding a record with fromId set to his id and toId set to the friend's id and isFriend=true.
To accept the request, the other user does the same but ids reversed.
They are only friends when both records exist and both have isFriend=true.
I'm trying to make a query that lists a users' friends given an ID (WHERE userId = x)
This is what I started with:
SELECT "a"."fromId" AS "userId1", "a"."toId" AS "userId2", "b"."fromId" AS "userId2", "b"."toId" AS "userId1"
FROM "Relationship" a
INNER JOIN "Relationship" b
ON "a"."fromId" = "b"."toId" AND "b"."fromId" = "a"."toId"
WHERE "a"."isFriend" = true AND "b"."isFriend" = true
This is the result I get with
With this, I'm able to get only the relationships that have records in both directions (friends), but what I'm trying to get (if possible), are only the IDs of the friends of a user
Thanks
select *
from "Relationship" a
where
a."fromId" = x and a."isFriend" and
exists (
select 1
from "Relationship" b
where
b."toId" = x /* b."toId" = a."fromId" */ and
b."isFriend");
Related
Brand new to SQL, so apologies that I don't really know how to word the question or find an existing answer. Let me explain further. I'm creating a Chat app for fun with a DM system. I have a table (dms_history) setup that has a row gen. for every new distinct chat between 2 users w/ the last DM being sent between the 2 users. eg:
CREATE TABLE users (
uid SERIAL PRIMARY KEY,
pid VARCHAR(40),
uname VARCHAR(50) NOT NULL UNIQUE,
email valid_email,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE dms (
dmid SERIAL PRIMARY KEY,
uid INT NOT NULL REFERENCES users(uid),
recip INT NOT NULL REFERENCES users(uid),
msg TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- TABLE I'M TALKING ABOUT
CREATE TABLE dms_history (
user1 INT REFERENCES users(uid),
user2 INT REFERENCES users(uid),
last_dm INT REFERENCES dms(dmid),
PRIMARY KEY(user1, user2),
CHECK (user1 < user2)
);
Say I'm trying to get all the data w/ joins on this table (dms_history) for client user uid#2. eg:
SELECT
u1.uid as u1id,
u1.uname as u1name,
u2.uid as u2id,
u2.uname as u2name,
dms.dmid,
dms.msg
FROM dms_history h
INNER JOIN users u1 ON h.user1 = u1.uid
INNER JOIN users u2 ON h.user2 = u2.uid
INNER JOIN dms ON h.last_dm = dms.dmid
WHERE u1.uid = 2 OR u2.uid = 2;
That query I thought of is close to what I want, but what I really want is only to show the user opposite of the client user being queried (so NOT user uid#2 alice) along w/ the last message sent. How do I filter or UNION? those columns into a new column. Picture to explain what I want:
Think of Twitter DMs and how it shows the users you're DMing and a snippet of the last message sent.
Apologies if I did a poor job explaining, it's not my strong suit.
After doing some more reading the past few hours I found I could use subqueries with SELECTs and UNIONs to achieve what I was after. Not sure how efficient it is, but it works.
WITH chats AS (SELECT * FROM dms_history h WHERE h.user1 = 2 OR h.user2 = 2)
SELECT
chats2.user1 as recip_id,
u.uname as recip_uname,
chats2.last_dm as dmid,
dms.msg,
dms.created_at
FROM (
SELECT chats.user1, chats.last_dm FROM chats
UNION
SELECT chats.user2, chats.last_dm FROM chats
) AS chats2
INNER JOIN users u ON chats2.user1 = u.uid
INNER JOIN dms ON chats2.last_dm = dms.dmid
WHERE chats2.user1 != 2;
I have a table friends, which contains the following columns:
friend_id and friend_of (both are storing unique user ids)
lets say the table friends contains the following data:
friend_id | friend_of
-------------------------
123 | 456
456 | 789
456 | 123
So this means that:
user with id=123 have one friend with id=456
user with id=456 have two friends with ids=123 (friend_1) & 789(friend_2)
user with id=789 have one friwnd with id=456
I want to write a query that given a single user id shows every friend that this user has (with their ids).
For example:
if given user with id=123 the output would be users with ids=456
if given user with id=789 the output would be users with ids=456
if given user with id=456 the output would be users with ids=123 and 789
Can you help me with the query I need?
(select friend_id as all_friends from friends where friend_of=ID)
uninon
(select friend_of as all_friends from friends where friend_id=ID)
I suppose you are interested in the case where an id exists only in one of the columns. Above query would address this. Note that union is used here and not union all as unique values are required.
select friend_id, friend_of
where friend_id = '456'
just change ID to get desire ouput
Just use union
Declare #id int = 1;
select f.friendof from
#YourTableName as f where f.friendId = #id
union
select f.friendId from
#YourTableName as f where f.friendof = #id
You can use the query SELECT * FROM friends WHERE friend_id='456', which should get all of the friends of 456. Then do a join on your "users" table using the foreign key friend_of.
EDIT: I didn't realize friends was a two-way relationship. In that case, use a UNION first, some of the other responses talk about it. :)
I am stuck a bit on this step: there are two tables:
booking (bookingId, id, userId)
timetableSlot (id,classId)
"id" linkes both tables.
Task - to show all classes,booked by user.
In the Servlet i can select all bookings for particular user from the booking table:
int userId=Integer.parseInt(request.getParameter("loggedInUserId"));
BookingDB allUserBookings = new BookingDB();
Collection<BookingDB> userBookings = new ArrayList<BookingDB>();
userBookings = allUserBookings.displayUserBookings(userId);
The result is a collection of records for one user bookings with many timetable slot ids. How can I pass all those ids to select corresponding records from timetableSlot table? Select collection based on collection? Thank you
SELECT * FROM ttslot WHERE id IN (
SELECT id FROM booking WHERE booking.userId=76
)
I've inherited a system using SQL Server (2008 R2) with two tables that cover system messaging. A message has a one to many relationship, it can be sent to multiple users.
Primary table, Messaging, looks like:
Id (PK, auto increment)
Subject
MessageBody
CreatorEmployeeId
ConversationId
IsConversationStarter (bool)
Secondary table, MessagingDetails, looks like:
ID (PK, auto increment)
MessageId (FK to Messaging PK)
RecipientEmployeeId
ConversationId
IsRead (bool)
If that's not clear, a new message is put into the Messaging table with an employee Id for who created the message, and new Conversation Id is created. Then X number of rows will be inserted into MessagingDetails, one per recipient, with references back to the Messaging table and using the same Conversation Id.
Any new replies will look the same, reply message goes into the Messaging table, recipient details go into MessagingDetails using the same Conversation Id, so that you can pull a whole message thread by one number.
This gets sloppy when you're trying to get a count of all unread messages that you've created or that have been sent to you. Here's an existing query that gets all of the unread messages sent to the logged-in user by other users in the system, where they created the message originally:
SELECT * FROM dbo.Messaging m
INNER JOIN dbo.MessagingDetails m1 on m.Id = m1.MessageId
INNER JOIN dbo.MessagingDetails m2 on m1.ConversationId = m2.ConversationId
WHERE m1.RecipientEmployeeId = #employeeId
AND m.IsConversationStarter = 1
AND m.ConversationId = m1.ConversationId
AND m2.IsRead = 0
AND m2.RecipientEmployeeId == #employeeId
Then to find all messages that the employee created but have unread replies, you have to do an almost identical query, swapping out the first part of the WHERE clause for:
m.CreatorEmployeeId = #employeeId
I loathe the inner joining the same table twice, once to itself. Given that schema outlined above, is there a better way to write these queries?
For "messages send by employee that have unsent replies", I think this solves the problem:
with EmployeeCreatedMessages as (
select distinct MessageId
from Messaging
where m.CreatorEmployeeId = #employeeId
)
select distinct MessageId
from MessageDetails md
where md.MessageId in (select MessageId from EmployeeCreatedMessages) and
md.IsRead = false
I'm not sure what information you want about the message. This just gives the message id.
The same approach works for all messages sent to users by others:
with OtherCreatedMessages as (
select distinct MessageId
from Messaging
where m.CreatorEmployeeId <> #employeeId
)
select distinct MessageId
from MessageDetails md
where md.MessageId in (select MessageId from OtherCreatedMessages) and
md.IsRead = false and
md.RecipientEmployeeId = #employeeid
Your description and your question don't mention conversionid. Is this relevant?
In order to get rid of that second join onto dbo.MessagingDetails, this query should be equivalent to yours.
SELECT * FROM dbo.Messaging m
INNER JOIN dbo.MessagingDetails m1 on m.Id = m1.MessageId
WHERE m1.RecipientEmployeeId = #employeeId
AND m.IsConversationStarter = 1
AND m.ConversationId = m1.ConversationId
AND EXISTS(SELECT * FROM dbo.MessagingDetails m2
WHERE m1.ConversationId = m2.ConversationId
AND m2.IsRead = 0 AND m2.RecipientEmployeeId == #employeeId)
I don't think it will be any more efficient though, you'd have to check the execution plan.
I am trying to create a View with SQL Server 2008 that can enable me to see if user a and b have mutual friends.
Use a and b are stored in a table called Friendships as Sender and Recipient with a IsPending column indicating if the friendship has been approved by the Recipient.
Anyway the main table is like this:
Sender | Recipient | IsPending
(Stored on a single row.)
How can I create a view that returns an extra column called HasMutual with a 0 if false or 1 if true?
Thanks.
I wish I was smart enough to figure out this query!
I can't believe the first two answers each got an up-vote. And this is not trivial as Ben Thul has claimed!
Since this is so difficult to solve with a single query, would you consider a different approach?
How about a stored procedure that takes in a pair of users, and then lists out their mutual friends?
(I'm assuming IsPending = 1 means they aren't friends yet)
CREATE PROCEDURE find_mutual_friends
(
#user1 varchar(255),
#user2 varchar(255)
)
as
SELECT
Friends
FROM
(SELECT
Friendships.Sender as Friends
FROM
Friendships
WHERE
Friendships.Recipient = #user1
and Friendships.IsPending = 0
UNION ALL
SELECT
Friendships.Recipient as Friends
FROM
Friendships
WHERE
Friendships.Sender = #user1
and Friendships.IsPending = 0) FriendsTempTable
WHERE
FriendsTempTable.Friends in
(SELECT
Friendships.Sender as Friends
FROM
Friendships
WHERE
Friendships.Recipient = #user2
and Friendships.IsPending = 0
UNION ALL
SELECT
Friendships.Recipient as Friends
FROM
Friendships
WHERE
Friendships.Sender = #user2
and Friendships.IsPending = 0)
CREATE VIEW ViewName
AS
SELECT
Sender , Recipient , IsPending, IsPending AS HasMutual
FROM myTable