How to construct SQL query to select chat participants - sql

I have 3 tables. Users(id, fullname), Chats(id, name) and Chats_Participants(chatId, userId). I need to select all the chats in which user with specified id consists. For example:
Chats:
1. 1, 'Test'
Users:
1. 1, 'Test user'
2. 2, 'Test user2'
Chat_Participants:
1. 1(chatId), 1(userId)
2. 1(chatId), 2(userId)
As a result, I need something like this:
1(chatId) 'Test'(chatName) participants(array of users in chat)
First I've wrote this:
select chats.*, json_agg(users) as participants
from chats
inner join chats_participants c2 on chats.id = c2."chatId"
inner join users on c2."userId" = users.id
where users.id = $userId
group by chats.id;
but this query selects only one participant

You can try with array_agg in postgresql. Demo here. Users table is not linked here, printing user id from chat_participants table instead.
SELECT chats.chat_id,chats.name, array_agg(userid order by chats.chat_id)
FROM chats
INNER JOIN chat_participants ON chats.chat_id = chat_participants.chat_id
GROUP BY chats.chat_id,chats.name

You seem to want:
SELECT c.chat_id, c.name,
array_agg(cp.userid order by cp.user_id) as users
FROM chats c INNER JOIN
chat_participants cp
ON c.chat_id = cp.chat_id
GROUP BY c.chat_id, c.name
HAVING SUM( (cp.userid = $userid)::int ) > 0;
This returns only chats that have your user of interest.

Related

Return Duplicate emails along with User Ids that are different

I'm running into an issue with a duplicate query and I hope you guys can help.
Essentially what I want to do is find and list of the duplicate emails associated with different userids
My query is:
select UserId, acitveid, email, userstatusid
from (select u.UserId, u.acitveid, cd.email, u.userstatusid,
count(*)over (partition by cd.email) as cnt
from ContactDetails cd
join UserContactDetails ucd on ucd.ContactDetailsId = cd.ContactDetailsId
join dbo.[User] u on u.UserId = ucd.UserId ) ua
where cnt >1
The issue I have with the above query is that it is returning the same userids for some of the results so it looks like:
Userid AcitveId email UserStatusid
123 1 abc#123.com 1
123 1 abc#123.com 1
135 1 efg#123.com 1
142 1 efg#123.com 1
The results Im looking for are simply:
Userid AcitveId email UserStatusid
135 1 efg#123.com 1
142 1 efg#123.com 1
WITH base AS (
SELECT DISTINCT u.UserId
,u.acitveid
,cd.email
,u.userstatusid
,
FROM ContactDetails cd
JOIN UserContactDetails ucd ON ucd.ContactDetailsId = cd.ContactDetailsId
JOIN dbo.[User] u ON u.UserId = ucd.UserId
)
,duplicate_emails AS (
SELECT email
,count(userId) AS cnt
FROM base
GROUP BY 1
HAVING count(userId) > 1
)
SELECT b.*
FROM base b
JOIN duplicate_emails de ON b.email = de.email
A self join across Email = email and id <> id would work fine here. That said, your request and lack of sample data means that we are largely guessing based off the query and sample output you have provided. The below should get you pretty close and, if you update your OP, I am sure we can get you exactly what you're after.
SELECT ActiveUser.UserID Active_UserID,
ActiveUser.ActiveID Active_ActiveID,
ContactDetails.email AS Email,
DuplicateUser.UserID AS Dup_UserID,
DuplicateUser.ActiveID As Dup_ActiveID
FROM ContactDetails INNER JOIN
ContactDetails AS Duplicate ON ContactDetails.email = Duplicate.email AND ContactDetails.UserID <> Duplicate.UserID INNER JOIN
UserContactDetails AS ActiveUserContactDetails ON ActiveUserContactDetails.ContactDetailsID = ContactDetails.ContactDetailsID INNER JOIN
dbo.[User] AS ActiveUser ON ActiveUser.UserID = ActiveUserContactDetails.UserID INNER JOIN
UserContactDetails AS DuplicateUserContactDetails ON DuplicateUserContactDetails.ContactDetailsID = Duplicate.ContactDetailsID INNER JOIN
dbo.[User] AS DuplicateUser ON DuplicateUser.UserID = UserContactDetails.UserID

Subquery SQL for link name and firstname

Hello I would like to retrieve the name and the first name in the user table thanks to the id contained in the message table (id_receive and id_send) in sql via a subquery
SELECT user.nom FROM user
WHERE user.id IN (
SELECT message.id_send, message.id_receive FROM message WHERE message.id=1
)
```
I would recommend using EXISTS, twice:
SELECT u.nom
FROM user u
WHERE EXISTS (SELECT 1 FROM message m WHERE m.id = 1 AND u.id = id_send) OR
EXISTS (SELECT 1 FROM message m WHERE m.id = 1 AND u.id = id_receive) ;
However, a JOIN might also be appropriate:
SELECT u.nom
FROM user u JOIN
message m
ON u.id IN (m.id_send, id_receive)
WHERE m.id = 1;
I suspect it isn't actually what you want but it looks like this is what you're trying to do:
SELECT user.nom FROM user
WHERE user.id IN (
SELECT message.id_send FROM message WHERE message.id=1
UNION ALL
SELECT message.id_receive FROM message WHERE message.id=1
)
The query that drives the IN should return a single column of values
Try and conceive that in works like this:
SELECT * FROM t WHERE c IN(
1
2
3
)
Not like this:
SELECT * FROM t WHERE c IN(
1 2 3
)
Nor like this:
SELECT * FROM t WHERE c IN(
1 2 3
4 5 6
)
It might help you reember that the query inside it must return a single column, but multiple rows, all of qhich are searched for a matching value c by IN
Small addition to your original query to make it working:
SELECT user.nom FROM user
WHERE user.id IN (
SELECT unnest(array[message.id_send, message.id_receive])
FROM message
WHERE message.id=1
)

SQL - Return most recent row from history table

I am working with Salesforce Lead and Contact data ('people') and parsing the record ownership history to see if a certain type of user currently owns or previously owned one of these people.
There are instances where one person or multiple people may have owned a record, in which case I want to return the more recent owner info (based on assignment date)
Here is my SQL, which returns duplicate rows for each Lead/Contact record.
with history as (
select
id,
leadid as lead_or_contact_id,
createddate,
field,
oldvalue,
newvalue
from salesforce_leadhistory
union
select
id,
contactid as lead_or_contact_id,
createddate,
field,
oldvalue,
newvalue
from salesforce_contacthistory
)
select
h.createddate as assignment_date,
h.lead_or_contact_id,
coalesce(old_user.name, new_user.name) as user_name,
coalesce(old_user.id, new_user.id) as user_id,
coalesce(old_user_role.name, new_user_role.name) as user_role
from history h
left join salesforce_user new_user on new_user.id = h.newvalue
left join salesforce_userrole new_user_role on new_user_role.id = new_user.userroleid
left join salesforce_user old_user on old_user.id = h.oldvalue
left join salesforce_userrole old_user_role on old_user_role.id = old_user.userroleid
where
field = 'Owner'
and ( old_user_role.name like 'SDR%' or new_user_role.name like 'SDR%' )
This returns, for example, two rows that refer to the same person record:
assignment_date lead_or_contact_id user_name user_id user_role
2020-01-01T00:42:37.000+00:00 00QXYZ Joe Jones 123 SDR - EMEA
2020-10-14T03:25:39.000+00:00 00QXYZ Max Clark 456 SDR - USA
In this instance, I would prefer all of the data from the second row (assignment date of 2020-10-14, user_name of Max Clark, user_id 456, and user_role "SDR - USA" to be returned since that is the most recent assignment history.
How can I accomplish this?
You can use row_number()
select * from
(
select
h.createddate as assignment_date,
h.lead_or_contact_id,
coalesce(old_user.name, new_user.name) as user_name,
coalesce(old_user.id, new_user.id) as user_id,
coalesce(old_user_role.name, new_user_role.name) as user_role,row_number() over(partition by h.lead_or_contact_id order by h.createddate desc) as rn
from history h
left join salesforce_user new_user on new_user.id = h.newvalue
left join salesforce_userrole new_user_role on new_user_role.id = new_user.userroleid
left join salesforce_user old_user on old_user.id = h.oldvalue
left join salesforce_userrole old_user_role on old_user_role.id = old_user.userroleid
where
field = 'Owner'
and ( old_user_role.name like 'SDR%' or new_user_role.name like 'SDR%' )
)A where rn=1

SQL Server - Get Distinct Ids from 2 column and store in one coulmn table

I have the following table
user_one user_two
20151844 2016000
20151844 2017000
2018000 20151844
20151844 20151025
20151036 20151844
Generated by the following query
select * from [dbo].[Contact] C
where C.user_one=20151844 or C.user_two=20151844
I want to get the following result excluding the current user Id 20151844
contact_Ids
2016000
2017000
2018000
20151025
20151036
What is the best optimized way to accomplish it? knowing that i want to join the ids to get the contact name form the user table.
Here's my tables:
Contact
user_one (int FK User.user_id), user_two (int FK User.user_id), status, action_user (int)
User
user_id (int PK), name , ...
another option: iif
select iif(C.user_one=20151844,C.user_two,C.user_one) as contact_IDs
from [dbo].[Contact] C
where C.user_one=20151844 or C.user_two=20151844
Use UNION and INNER JOIN:
SELECT c.[contact_Ids],
u.[name]
FROM (SELECT [user_one] [contact_Ids]
FROM [Contact]
WHERE [user_one] <> 20151844
AND [user_two] = 20151844
UNION
SELECT [user_two] [contact_Ids]
FROM [Contact]
WHERE [user_two] <> 20151844
AND [user_one] = 20151844) c
INNER JOIN [User] u
ON u.[user_id] = c.[contact_Ids]
ORDER BY c.[contact_Ids];
Use apply :
select tt.contact_Ids
from table t cross apply (
values (user_one), (user_two)
) tt (contact_Ids)
group by tt.contact_Ids
having count(*) = 1;
Set operations Union and except works the best.
;with ids as (
select user_one id from contact
union
select user_two from contact
except
select 20151844
)
select u.*
from [user] u
inner join ids on u.user_id = ids.id

Select Statement with INNER JOIN AND CASE

I'm trying to get sql statement to link from one table to another and use a case (or if) if the user has accesslevel 1 then the statement should be select * from campaigns, whereas if ur not accesslevel 1 u should get the select statement as :
select * from campaigns WHERE campaign_Creator = ${user_ID}
SELECT * FROM campaigns
INNER JOIN users ON campaigns.CAMPAIGN_CREATOR = users.USER_ID
CASE WHEN users.USER_ACCESSLEVEL = 1
THEN SELECT * FROM campaigns
ELSE select * from campaigns WHERE CAMPAIGN_CREATOR = ${user_ID};
How would I go around creating such a statement? I've been trying to look it up but i just get more confused as to how to go around with this.
Perhaps this is what you want?
SELECT * FROM campaigns
INNER JOIN users ON campaigns.CAMPAIGN_CREATOR = users.USER_ID
WHERE users.USER_ACCESSLEVEL = 1
OR CAMPAIGN_CREATOR = ${user_ID};
I agree with the solution of our friend and complementing follow my suggestion.
SELECT *
FROM campaigns
INNER JOIN users ON campaigns.CAMPAIGN_CREATOR = users.USER_ID
AND (users.USER_ACCESSLEVEL = 1 OR (users.USER_ACCESSLEVEL != 1
AND CAMPAIGN_CREATOR = ${user_ID}))