Weave rows representing email messages into send & reply conversation threads - sql

I have (two) tables of SENT and RECEIVED email messages exchanged between patients and their doctors within an app. I need to group these rows into conversation threads exactly the way you would expect to see them in your email inbox, but with the following difference:
Here, “thread” encompasses all back-and-forth exchanges between the same 2 users. Thus, each single unique pair of communicating users constitutes 1 and only 1 thread.
The following proof-of-concept code successfully creates a notion of “thread” for a single instance where I know the specific patient and doctor user IDs. The parts I can’t figure out are:
(1) how to accomplish this when I’m pulling multiple patients and doctors from tables, and then
(2) to sort the resulting threads by initiating-date
SELECT send.MessageContent, send.SentDatetime, rec.ReadDatetime, other_stuff
FROM MessageSend send
INNER JOIN MessageReceive rec
ON send.MessageId = rec.MessageId
WHERE
( send.UserIdSender = 123
OR rec.UserIdReceiver = 123 )
AND
(send.UserIdSender = 456
OR rec.UserIdReceiver = 456)

If MessageID is unique for a conversion, You can order the messages using the send and received date time.
If you want to filter for particular doctor or patient ,you can include it in the where clause.
SELECT send.MessageContent, send.SentDatetime, rec.ReadDatetime, other_stuff
FROM MessageSend send
INNER JOIN MessageReceive rec
ON send.MessageId = rec.MessageId
ORDER BY send.MessageId,send.SentDatetime, rec.ReadDatetime

Related

Case in SQL join not stopping at first successful match

I'm currently working with a B2B sales database that doesn't have a unique identifier for each customer. New records are allocated an ID code when loaded but the a person can have more than one ID code for various reasons.
The business regularly runs events where they capture registration data. I'm trying to match the event data (pre DB load) to a table of existing contacts. This is proving challenging as nothing is unique (not even email addresses as they can be shared or associated with multiple records in the contacts master table).
I need to run some code to flag where new contacts exist in the database already. My thinking led me to a cascading process of 'try this, if not then try this' etc. using a CASE in the join.
However, it's not stopping at the first condition that's met and just returns everything that meets any condition - resulting in the same record in the contacts master being joined on more than once and duplicated in the results in many cases.
Is there a way to improve the join or is there just a better way to achieve matching across these data sets?
SELECT nc.email
,nc.firstname
,nc.lastname
,nc.company
,cm.id_code
,cm.sales_region
FROM [sales].[new_contacts] nc
LEFT JOIN [sales].[contact_master] cm
ON CASE when nc.email = cm.email AND nc.fullname = cm.fullname and nc.company = cm.company then 1
when nc.email = cm.email AND nc.fullname = cm.fullname then 1
when nc.email = cm.email then 1
when nc.fullname = cm.fullname then 1
else 0 END = 1

How to sort friends by last message time like whatsapp

I'm working on a chat app and I want to get a query that pulls out the list of friends and sorts them by last message time just the way whatsapp does its own.
Three tables in the database are important.
Table name: UsersPurpose: It stores the list of all registered users in the chat app.
Columns:- sn, matricno, fullname, password, faculty, department, level, year, study_centre, gender, email,phoneno and picture.
Table name: Friends
Purpose: It stores all the list of friends and friend requests.
Columns:- sn, user1, user2, date_initiated,status(1=request sent, 2=they are friends, 3= They are no longer friends), date_accepted, date_unfriend
Table name: Messages
Purpose:- It stores all the messages that have been sent between friends
Columns:- sn, sender, recipient, content, date, mread(to indicate if the recipient has read the message)
So far, this query pulls the list of friends just the way I want, what is left is to combine the messages table and sort it using the date column
SELECT *
FROM users
WHERE matricno IN (SELECT user2
FROM friends
WHERE user1 = 'NOU1213131415'
AND STATUS = '2'
UNION
SELECT user1
FROM friends
WHERE user2 = 'NOU1213131415'
AND STATUS = '2')
The picture below is an example of the chat list it pulls out
I don't know the SQL dialect you use and didn't tested it, but maybe you can do something like this:
SELECT
u.*,
(SELECT MAX(date) FROM messages m WHERE m.sender = u.matricno OR m.recipient = u.matricno) AS max_date
FROM users u
JOIN friends f ON (u.matricno = f.user1 OR u.matricno = f.user2) AND f.status = 2
WHERE u.matricno = 'NOU1213131415'

SQL Query to get specific result. It can be Lambda or LINQ

It is not a general question. It is all about my 3 tables and I couldn't figure out where to start.
Basically I have got 3 tables. ClientModels, DolsMcaItemModels and DolsMcaClientModels.
ClientModels - All the clients and their ClientID
DolsMcaItemModels - List of documents, there is a mandatory column.
DolsMcaClientModels - This table keeps all client DolsMcaItemModels.
I am trying to get list of clients who don't have mandatory documents in DolsMcaClientModels.
For example, if I have got a Mandatory "Passport" Document in DolsMcaItemModels and I want to get a list of clients who don't have a passport.
CLIENT TABLE
SELECT C.[ClientID]
,[ClientName]
,[ClientDOB]
FROM [dbo].[ClientModels]
DOCUMENT LIST
SELECT [DolsMcaItemID]
,[DolsMcaItemName]
,[DolsMcaItemMandatory]
,[DolsMcaItemStatus]
FROM [dbo].[DolsMcaItemModels]
WHERE [DolsMcaItemStatus] = true
Client Document Table
SELECT [DolsMcaClientID]
,[DolsMcaItemID]
,[ClientID]
,[DolsMcaClientItemStatus]
FROM [dbo].[DolsMcaClientModels]
So far what i did
List of clients who don't have any documents
SELECT C.[ClientID]
,[ClientName]
,[ClientDOB]
FROM [dbo].[ClientModels] C
LEFT JOIN [DolsMcaClientModels] CI ON C.ClientID = CI.ClientID
WHERE CI.ClientID IS NULL
and list mandatory is missing.
SELECT I.[DolsMcaItemID]
,[DolsMcaItemName]
,[DolsMcaItemLevel]
,[DolsMcaItemMandatory]
,[DolsMcaItemStatus]
FROM [dbo].[DolsMcaItemModels] I
LEFT JOIN [DolsMcaClientModels] CI2 ON I.DolsMcaItemID = CI2.DolsMcaItemID
WHERE CI2.DolsMcaItemID IS NULL AND [DolsMcaItemMandatory] = 1
I don't know how to combine this together.

Need to return multiple entries from a single field in One Table

So Here is the problem I have a requirement where I need a customer type to equal two different things.
To Cover the requirement I don't need the customer type to equal Client, or Non client but equal Client, and Non_Client. Each Customer_No can have multiple Customer Types
Here is an example of what I have worked on so far. If you know a better way of optimizing this as well as solving the problem please let me know.
The out put should look like this
CustomerID CustomerType CustomerType
--------------------------------------
2345 Client NonClient
Select TB1.Customer_ID, IB1.Customer_Type, AS Non_client IB1.Customer_Type AS Client
From Client TB1, Client_ReF XB1, Client_Instr IB1, Client_XREC FB1
Where XB1.Client_NO = TB1.Client_NO
AND FB1.Client_ACCT = TB1.ACCT
AND XB1.Client_Instruct_NO = IB1.Client_Instruct_NO
AND FB1.Customer_ID= TB1. Client_NO
AND IB1.Client = 'Client'
AND IB1.Non_Client = 'NonClient'
I have omitted a few other filters that I felt were unnecessary. This also may not make sense, but I tried to change up the names of stuff as to keep myself in compliance.
First a small syntactic error:
You mustn't have a comma before the "AS Non_client "
Then what you are trying to do is make 1 value equal 2 different things for the same column which can never be true:
IB1.Customer_Type for 1 record can never be equal to "Client" and "NonClient" simultaneously.
The key here is that 1 customer can have multiple records and the records can differ in the customer_type. So to use that we need to join those records together which is easy since they share a Customer_ID:
Select TB1.Customer_ID,
IB1.Customer_Type AS Client,
IB2.Customer_Type AS Non_client
From Client TB1,
Client_ReF XB1,
Client_Instr IB1,
Client_Instr IB2,
Client_XREC FB1
Where XB1.Client_NO = TB1.Client_NO
AND FB1.Client_ACCT = TB1.ACCT
AND XB1.Client_Instruct_NO = IB1.Client_Instruct_NO
AND FB1.Customer_ID= TB1.Client_NO
AND IB1.Client = 'Client'
AND XB1.Client_Instruct_NO = IB2.Client_Instruct_NO
AND IB2.Non_Client = 'NonClient';
The above may not actually work due to me not fully understanding your data and structures but should put you on the right path. Particularly around the join of IB2 with XB1, you might have to join IB2 with all the same tables as IB1.
A better way than that however, and i'll leave you to research it, is using the EXISTS statement. The difference is that the above will join all records for the same customer together whereas EXISTS will just be satisfied if there's at least 1 instance of a "NonClient" record.

Join on multiple fields in Pig

I'm learning Pig and not sure how to do the following. I have on file that stores a series of metadata about chat messages:
12345 13579
23456 24680
19350 20283
28394 20384
10384 29475
.
.
.
The first column is the id of the sender and the second column is the id of the receiver. What I want to do is count how many messages are being sent from men to women, men to men, women to men, and women to women. So I have another file which stores user id's and gender:
12345 M
23456 F
34567 M
45678 M
.
.
.
So the Pig script might start out as follows:
messages = load 'messages.txt' as (from:int, to:int);
users = load 'users.txt' as (id:int,sex:chararray);
From there I'm really not sure what the next step to take should be. I was able to join one column at a time of messages to users, but not sure how to join both columns and then do the subsequent grouping.
Any advice/tips would be super helpful.
I guess what you want is to join then group and count your data.
joinedSenderRaw = JOIN users BY id, messages BY from;
joinedSender = FOREACH joinedSenderRaw
GENERATE messages::from as sender_id,
users::sex as sender_sex,
messages::to as receiver_id;
joinedAllRaw = JOIN joinedSender BY receiver_id, users BY id;
joinedAll = FOREACH joinedAllRaw
GENERATE joinedSender::sender_id,
joinedSender::sender_sex,
joinedSender::receiver_id,
users::sex as receiver_sex;
grouped = GROUP joinedAll BY (sender_sex, receiver_sex);
result = FOREACH grouped
GENERATE $0.sender_sex AS sender_sex,
$0.receiver_sex AS receiver_sex,
COUNT($1) AS your_stat;
I did not test it but something like this should work.