Linq to SQL distinct join and group - linq-to-sql

I've been struggling with this Linq query...
I have the following 2 tables:
1) EmailRunHeaders - with columns: Id, EmailRunId, EmailId
2) EmailTrackers - with columns: Id, EmailId
Every day a batch of emails are sent. A unique "EmailRunId" is assigned to a batch/group of emails and each email is assigned an "EmailId". This info is then stored in the "EMailHeaders" table.
So, each emailId in the table will be unique, but the EmailRunId will appear more than once..since there is more than one email in each "batch" or run.
When an email is opened, using a HTTP handler, the open is logged in the EmailTracker table...where the particular EmailId is then stored. Since an email could be opened more than once, it is possible that a EmailId could appear more than once in this table.
I need the total number of emails opened, without double counting emails opened more than once, for every email run.
This is what I have so far. The nested query works fine..returning the total number of emails opened for each run, but only if there where at least 1 opened for each run.
I then tried wrapping that in another join to return all the distinct EmailRunIds from the header table..but that is where I am stuck..I don't know how to get the EmailRunId from "ah1".
from arh1 in EmailRunHeaders.Select(x => x.EmailRunID).Distinct()
join eo in
(from et in EmailTrackers
join arh2 in EmailRunHeaders
on et.EmailId equals arh2.EmailID.ToString() into j1
from j2 in j1.DefaultIfEmpty()
group j2 by j2.EmailRunID
into g
select new {runId = g.Key, count = g.Count()})
on arh1 equals eo.runId into tg
from tg2 in tg.DefaultIfEmpty()
select tg2

Related

Update field in table with count of rows in another

I am building some custom email performance reporting in Marketing Cloud. I have one table which has a list of the emails sent in the last 30 days. It has a unique identifier, JobID. It has a few more columns where I want to insert for example how many times email was opened.
JobID EmailName Opens
37735 Test Email
I also have a table containing a list of all the opens of the emails sent in the last 30 days (using an inner join on the first table). I want to count the number of rows with job no. 37735 for example, and use this value to populate 'opens' in the above table.
JobID Subscriber DateOpened
37735 test#test.com 14/09/2017
37735 test2#test.com 14/09/2017
So from the above, I want a '2' in the 'Opens' column of the first table. Can anyone help?
If I understand correctly, you want an update. If so:
update table1 t1
set opens = (select count(*)
from table2 t2
where t2.jobid = t1.jobid
)
where t1.jobid = 37735;

Query for average response time in mysql

I have a table with columns:
id , conversation_id , session_id , user_id , message , created_at
every time a user starts a conversation with an employee, a new session starts (different session number).all messages between every employees and users are stored in this table. the created_at column is a timestamp. I need to filter out sessions by employee number, and calculate the average response time between the first message a user sends and the first message sent back by a specific employee, for every session disregarding outlying data where either a customer or employee did not reply ( only one user in the session)
i know this is complicated but please help!
in this example in the user_id column, 4 is the employee ( keep in mind there are other employees). everytime a new conversation starts the session_id changes. i have to go through each session for a specific employee, take the timestamp of the first message sent by the customer as well as the employee, take the difference, sum all the differences and then take an average, while making sure that the session actually contains two users ( filtering outlying data).
So far, ive come up with this:
SELECT * FROM messages
WHERE session_id IN (
SELECT session_id FROM messages
WHERE user_id =4 )
GROUP BY session_id, user_id
to get the first message from each customer and employee (gives something like this)
so from this specific example, i would omit line 41040 as it only as the session contains only 1 person (column 3, id 1028) and is considered outlying data
I'm actually appalled by some of the comments... StackOverflow is meant to be a community for helping others. Why bother even taking up comment space if you're gonna complain about my ponctuation or give a vague, useless answer?
Anyways, i figured it out.
Basically, i joined the same table multiple times but only queried the necessary data. In the first join, I queried the messages table with the employee messages and grouped them by session number. In the second join, i did the same procedure but only extracted the messages from the user. By joining them on the session id, it automatically omits any sessions where either a user or employee is not present. By default, the groupby returns the first set of data from the group ( in this situation i didn't have to manipulate the groupby because I was actually looking for the first message in the session), I then took the average of the difference between the message timestamp for the user and employee.In this specific situation, the number 4 is the employee number. Here is what the query looks like Also, the HAVING AVG_RESP > 0 was necessary in this situation to remove outlying data when tests are performed :
SELECT AVG(AVG_RESP)
FROM(
SELECT TIME_TO_SEC(TIMEDIFF(t.created_at, u.created_at )) AS AVG_RESP
FROM (
SELECT * FROM messages
WHERE session_id IN (
SELECT session_id FROM messages
WHERE user_id = 4) AND user_id = 4
GROUP BY session_id
) AS t
JOIN(
SELECT * FROM messages
WHERE session_id IN (
SELECT session_id FROM messages
WHERE user_id = 4) AND user_id != 4
GROUP BY session_id
) as u
ON t.session_id = u.session_id
GROUP BY t.session_id
HAVING AVG_RESP > 0
) as ar
Hopefully this helps someone in the future, unlike the people who leave ridiculous, useless comments.

Update new column using If sum condition on existing fields

unique_id site status Final status
HMEX093 MEX025 Accepted Incomplete
HMEX093 HMEX056 Accepted Incomplete
HMEX093 LTY0014 Pending Incomplete
I want an update query to update Final status column depending if query on status.
every unique_id has multiple sites with different status.
I want to update final status column with if sum of condition.
for eg. unique_id HMEX093 has 3 sites with different sites. I want to check status of these sites,if sum(status='Accepted') of site >= 3 final status column should be updated with value Approved.
If there is atleast one pending status to corresponding sites of unique_id, final status shoul be updated as Incomplete as shown above.
please help.
I tried with Case when statement, but no success.
EDIT
Now that I realize the question was about MySQL, not Excel, I think something like the following query would work:
update
Sites
inner join
(
select
s1.unique_id,
if(s2.accepted_sites = count(*),'Accepted','Incomplete') as final_status
from
Sites s1
left outer join
(
select
unique_id,
count(*) as accepted_sites
from
Sites
where
status = 'Accepted'
group by
unique_id
) as s2 on s2.unique_id = s1.unique_id
group by
s1.unique_id
) s on s.unique_id = Sites.unique_id
set
Sites.final_status = s.final_status
What this query does:
The inner select statement counts the number of sites that are accepted for each unique ID.
The outer select statement compares the total number of sites for each unique ID and compares it with the number of accepted sites. If the counts are equal, the final status is "Accepted", otherwise, it is "Incomplete".
The update statement sets the final_status to the results of the outer select statement. (I wasn't able to test the update part, but hopefully it's at least close.)
Original answer for doing this in Excel
If your table is located at A1,
Try entering this array forumula* into cell D2 and copying is down to the last row of your table:
=IF(SUM(IF((A$2:A$10=A2)*(C$2:C$10="Accepted"),1,0))=COUNTIF(A$2:A$10,A2),"Accepted","Incomplete")
*Array formulas allows you to crunch numbers on entire columns of data at once, rather than just one row at a time. To enter an array formula, you need to type or paste in the formula then press Ctrl+Shift+Enter.
If you've done this successfully, the formula should gain curly braces around it, like this:
{=IF(SUM(IF((A$2:A$10=A2)*(C$2:C$10="Accepted"),1,0))=COUNTIF(A$2:A$10,A2),"Accepted","Incomplete")}
What this formula does:
The outer IF statement puts "Accepted" if the condition is true, otherwise, it puts "Incomplete"
The COUNTIF statement counts the number of IDs in the entire unique_id column that match the unique_id of the current row.
The SUM and inner IF statements add up the number of rows where the unique_id matches the unique_id of the current row and the status is "Accepted". (Note that, with an array formula, * means and.)
So, overall, the formula checks if the number times an ID is accepted is the same as the number of rows with than ID.
Here is my test table:
unique_id site status final_status
HMEX093 MEX025 Accepted Incomplete
HMEX093 HMEX056 Accepted Incomplete
HMEX093 LTY0014 Pending Incomplete
HMEX094 MEX025 Accepted Accepted
HMEX094 HMEX056 Accepted Accepted
HMEX094 LTY0014 Accepted Accepted
HMEX095 MEX025 Pending Incomplete
HMEX095 HMEX056 Pending Incomplete
HMEX095 LTY0014 Pending Incomplete

MySQL Query - Loading records if the owner is a friend

I've got a system on my website which is very similar to Facebook, where you can post statuses and your people can comment on your status, like it etc. This all gets inserted in the database in the following format, with child tables of the likes and comments with foreign keys set up in case the parent status gets deleted, the likes and comments get deleted with it.
I also have a friends table which contains the user ID of the user that started the friend request, the user ID of the user that has to either accept it or deny it, and the status of the record, whether it's accepted, denied or pending.
There's also a "users" table which contains the normal malarkey, such as emails, passwords etc. All records have a unique ID however, in the column "userID".
The query I have at the moment loads all statuses regardless of whether the status owner is your friend or not. The current query looks like this (I'm working in ColdFusion so ## are the variables passed to the function)
SELECT *,
(SELECT COUNT(*) FROM status_likes WHERE likeStatusID=statusID) AS StatusLikeCount,
(SELECT COUNT(*) FROM status_comments WHERE SID=statusID) AS StatusCommentCount
FROM status, users
WHERE statusOwner=userID
AND statusType='user'
ORDER BY statusDateTime DESC
LIMIT #args.indexStart#,#args.indexEnd#;
I need this query to only load statuses if the owner of the status is your friend. I can call a query to load a users friends and append a string containing the user ID's of all the friends, such as: "652,235,485,975" etc.
I tried doing an IN in the query so there was an extra line:
AND (statusOwner=#val(args.userID)# OR statusOwner IN (#usersFriendsString#))
However this brought back duplicate results and when I tried GROUP BY on the status owner, it didn't bring back records that it should have.
Any MySQL gurus out there able to help?
You should use something like that :
SELECT
s.*,
(SELECT COUNT(*) FROM status_likes WHERE likeStatusID=s.statusID) AS StatusLikeCount,
(SELECT COUNT(*) FROM status_comments WHERE SID=s.statusID) AS StatusCommentCount
FROM Users u
JOIN Friend f ON f.friendOwner = u.id
JOIN Status s ON s.statusOwner = f.id
WHERE u.id = <...>
ORDER BY s.statusDateTime DESC
You can use WHERE clause if you can't use a JOIN instruction.
Or you can use a IN instruction populated by a SELECT that retrieve all requiered status ids.

Generate a table from the data of another table

What I'm trying to do is that I have a table called messages. It has 5 fields ID, SENDER, RECIPIENT, MESSAGE and TIMESTAMP. Each user gets an id when he uses this app. Each message that he sends using this app gets stored in this table with the id of the recipient.
Now what I want is to be able to list the most recent message of each conversation and then list each conversation in order of the recency of their last message. Lets call this table CONVERSATIONS.
Each conversation between two users XX and YY is defined as a table generated by
SELECT * FROM MESSAGES WHERE SENDER=XX and RECIPIENT=YY ORDER BY TIMESTAMP
In CONVERSATIONS table we only want the most recent message of each of the conversations in the MESSAGES table.
I don't want to use PHP and was looking for a solution only using MySQL. Thank you.
If I understood you correctly, you may try something like this.
select MESSAGES.*,
concat(SENDER|RECIPIENT, "r", SENDER&RECIPIENT) as combo
from MESSAGES inner join (
select max(TIMESTAMP) maxtime,
concat(SENDER|RECIPIENT, "r", SENDER&RECIPIENT) as combo2
from MESSAGES group by combo2
) subq
on combo = combo2 and MESSAGES.TIMESTAMP = subq.maxtime
order by MESSAGES.TIMESTAMP desc
Here standard technique of grouping is used (from here), but also I used combo expression, which is commutative injection from (SENDER,RECIPIENT) to strings.
It'll return you all rows with max timestamps grouped by unordered pair {SENDER,RECIPIENT}