I have a table session as below:
sessionid conversationid agentid
SES153130074572578571 001a60f3-d95c-4434-a8c0-fabb7d815277_OD112807172056802000 igs.399760
SES15313020119321989 001a60f3-d95c-4434-a8c0-fabb7d815277_OD112807172056802000 hgs.20073
SES153130276854998136 001a60f3-d95c-4434-a8c0-fabb7d815277_OD112807172056802000 igs.100000000308235
SES153128080803552749 00803e49-0325-4bef-b133-8c5e97f2fccc_OD112706138643350000 hgs.20031
SES153128342589414965 00803e49-0325-4bef-b133-8c5e97f2fccc_OD112706138643350000 hgs.20031
SES153129466185930775 008bba3a-98fa-414a-8f99-96956513bc66_OD112757403158502000 igs.401836
SES153129612178429544 008bba3a-98fa-414a-8f99-96956513bc66_OD112757403158502000 hgs.20076
SES153129179161527928 00976601-aac7-4ec7-9e03-61cd59875650_Payment Related Queries hgs.20071
SES153129238786010778 00976601-aac7-4ec7-9e03-61cd59875650_Payment Related Queries igs.100000000307102
i want the rows where a conversationid is assigned to only one agent id (cases where one conversationid is assigned to more than one agentid would be omitted)
i.e. my output should be as below:
sessionid conversationid agentid
SES153128080803552749 00803e49-0325-4bef-b133-8c5e97f2fccc_OD112706138643350000 hgs.20031
SES153128342589414965 00803e49-0325-4bef-b133-8c5e97f2fccc_OD112706138643350000 hgs.20031
Kindly help with the query
select sessionid,agentid,conversationid from session as S
inner join
(
select agentid from session
group by agentid
having count(*)=1
) T
on S.agentid=T.agentid
Try the following:
select s.sessionid, s.agentid, s.conversationid
from session s
inner join
(
select conversationid
from session
group by conversationid
having count(distinct agentid) = 1
) uq
on s.conversationid = uq.conversationid
uq will contain all conversationid where the number of distinct agents is 1. Join that with the original data to get all rows for those conversationid.
Related
I Have this table:
[Messages table]
I need to find the number of uniqe conversation -
conversation is define as senderid sent msg to reciverid, and reciverid has replied (no matter how many times or the thread length, it will be count as 1 conversation).
so if senderid = 1, reeiver id =2
and in the next row senderid = 2 and reciever id =1 this is one conversation (till the end of time)
Im really stock and not sure how to proceed.
Thanks!
You can use the functions LEAST() and GREATEST() to create unique combinations of the 2 ids and aggregate:
SELECT COUNT(DISTINCT LEAST(m1.senderid, m1.receiverid), GREATEST(m1.senderid, m1.receiverid)) counter
FROM Messages m1
WHERE EXISTS (SELECT 1 FROM Messages m2 WHERE (m2.receiverid, m2.senderid) = (m1.senderid, m1.receiverid))
See the demo.
Results (for your sample data):
counter
2
Here's one option using a self join with least and greatest to get your desired results:
select count(*)
from (
select distinct least(m1.senderid, m2.senderid), greatest(m1.receiverid, m2.receiverid)
from messages m1
join messages m2 on m1.senderid = m2.receiverid and m1.receiverid = m2.senderid
) t
Query with OR which outputs wrong
SELECT DISTINCT
sm___employees.id,
sm___employees.employee_code,
sm___employees.leaving_date,
sm___employees.name_of_employee,
sm___employees.position,
sm___employees.rating,
sm___employees.entry_date
FROM
sm___employees
JOIN
sm___employee_skills
ON
sm___employees.id=sm___employee_skills.employee_id
WHERE
((sm___employee_skills.skill_id=1 AND sm___employee_skills.ans LIKE '%MBA%')
**OR**
(sm___employee_skills.skill_id=5 AND sm___employee_skills.ans IN (3)))
AND
sm___employees.rating IN (1)
ORDER BY
sm___employee_skills.date DESC
But I want it by And
SELECT DISTINCT
sm___employees.id,
sm___employees.employee_code,
sm___employees.leaving_date,
sm___employees.name_of_employee,
sm___employees.position,
sm___employees.rating,
sm___employees.entry_date
FROM
sm___employees
JOIN
sm___employee_skills
ON
sm___employees.id=sm___employee_skills.employee_id
WHERE
((sm___employee_skills.skill_id=1 AND sm___employee_skills.ans LIKE '%MBA%')
**AND**
(sm___employee_skills.skill_id=5 AND sm___employee_skills.ans IN (3)))
AND
sm___employees.rating IN (1)
ORDER BY
sm___employee_skills.date DESC
When am using first query with OR of MBA or 3, It gives me result for both which is correct as per OR operation
I want only those records which are having MBA AND 3 which gives me blank records when there are records available with this comparison
So please help me to resolve this.
Thank you in advance
To start with: DISTINCT often indicates a badly written query. This is the case here. You are joining records only to dismiss them later. If you want employee records, then select from the employee table. If you have criteria on the skills table check this in the WHERE clause. Don't join.
Then the WHERE clause looks at one row at a time. So neither skill_id = ... AND skill_id = ... nor skill_id = ... OR skill_id = ... can work for you. You must look up the skills table twice:
SELECT
id,
employee_code,
leaving_date,
name_of_employee,
position,
rating,
entry_date
FROM sm___employees
WHERE rating IN (1)
AND id IN
(
SELECT employee_id
FROM sm___employee_skills
WHERE skill_id = 1 AND ans LIKE '%MBA%'
)
AND id IN
(
SELECT employee_id
FROM sm___employee_skills
WHERE skill_id = 5 AND ans IN (3)
);
And here is a way to look up skills just once:
SELECT
id,
employee_code,
leaving_date,
name_of_employee,
position,
rating,
entry_date
FROM sm___employees
WHERE rating IN (1)
AND id IN
(
SELECT employee_id
FROM sm___employee_skills
WHERE (skill_id = 1 AND ans LIKE '%MBA%')
OR (skill_id = 5 AND ans IN (3))
GROUP BY employee_id
HAVING COUNT(DISTINCT skill_id) = 2 -- both skills
);
It seems strange though that you consider ans to be a string in one place (ans LIKE '%MBA%') and a number in another (ans IN (3)).
UPDATE: If you want to sort by skill date, you should consider by which skill's date. For this to happen, you would join, but not join the skills table, but the skills aggregate result. E.g.:
SELECT
e.id,
e.employee_code,
e.leaving_date,
e.name_of_employee,
e.position,
e.rating,
e.entry_date
FROM sm___employees e
JOIN
(
SELECT employee_id, MAX(date) AS max_date
FROM sm___employee_skills
WHERE (skill_id = 1 AND ans LIKE '%MBA%')
OR (skill_id = 5 AND ans = 3)
GROUP BY employee_id
HAVING COUNT(DISTINCT skill_id) = 2 -- both skills
) s ON s.employee_id = e.id
WHERE e.rating = 1
ORDER BY s.max_date;
Please try this :
SELECT DISTINCT
sm1.id,
sm1.employee_code,
sm1.leaving_date,
sm1.name_of_employee,
sm1.position,
sm1.rating,
sm1.entry_date
FROM sm___employees sm1
LEFT JOIN sm___employee_skills sm2 ON sm1.id = sm2.employee_id
WHERE ((sm2.skill_id=1 AND sm2.ans LIKE '%MBA%')
AND (sm2.skill_id=1 AND sm2.ans=3))
AND sm1.rating IN (1)
ORDER BY sm2.date DESC;
I've been stuck on this problem for far too long.
I have to merge 3 tables and do some counting of distinct values.
I have 3 tables
1.User_me
profileId( String )
responded( int 1 or 0)
2.Profiles
profileId ( String )
idLocation ( int )
3.lookup_location
id ( int )
location (String )
I can join User_me and Profiles ON User_me.profileId = Profiles.profileId
I can join Profiles and lookup_location ON Profiles.idLocation = lookup_location.id
Under Profiles I need to count the number of distinct values for idLocation where User_me.profileId = Profiles.profileId
I also need to count the number of Profiles.idLocation that have User_me.responded = 1
I have this:
SELECT lookup.location, count(*) as total
FROM User_me user
JOIN Profiles
ON user.profileId= profiles.profileId
JOIN lookup_location lookup
ON profiles.idLocation = lookup.id
GROUP BY profiles.idLocation
but I still need to have the column giving me the count where User_me.responded = 1
Something like:
SELECT lookup.location, count(*) as total, count(*) responded
If I'm understanding your question correctly, you can you a case statement in the count aggregate:
SELECT lookup.location, count(*) as total,
count(case when user.responded = 1 then 1 end) as responded
FROM User_me user
JOIN Profiles
ON user.profileId= profiles.profileId
JOIN lookup_location lookup
ON profiles.idLocation = lookup.id
GROUP BY profiles.idLocation
Since you're using MySQL, you can also use something like sum(user.responded = 1).
I have 1 table with tasks named opentask:columns: id,title,description,expires,creator_id,creator_name, executer_id, executer_name, priority_id, status_id1 table with users named user:
with columns: user_id, username
What I want is to create a query where there will be all columns from opentask table where the executer_id will be equal to the user_id of user table AND the creator_id will be equal to the user_id again. This creates a confusion because the first equality excludes the second.So I need somehow to create a query where I will include the usernames for the executer with something like where "opentask.executer_id=user_user_id" and at the same time I will include the username again (as a differend name?) for the creator with something like "where opentask.executer_id=user_user_id"So I try this, which of course I know that is missing something, can you help?
SELECT DISTINCT id, title, description, expires, creator_id, executer_id, oc_opentask.priority_id, oc_opentask.status_id, priority_name, status_name, user_id, username, (SELECT username FROM oc_opentask, oc_user WHERE oc_opentask.creator_id=oc_user.user_id) AS username2 FROM oc_opentask, oc_opentask_priority, oc_user, oc_opentask_status WHERE oc_opentask.priority_id=oc_opentask_priority.priority_id AND oc_opentask.executer_id=oc_user.user_id AND oc_opentask.status_id=oc_opentask_status.status_id ORDER BY oc_opentask.expires DESC
ReJOIN the table oc_user twice with different aliases creators and executers like so:
SELECT DISTINCT
t.*,
creators.user_name 'Creator name',
executers.username 'Executor name',
tp.priority_name,
s.status_name
FROM oc_opentask t
INNER JOIN oc_opentask_priority tp ON t.priority_id = tp.priority_id
INNER JOIN oc_user executers ON t.executer_id = executes.user_id
INNER JOIN oc_user creators ON t.creator_id = creators.user_id
INNER JOIN oc_opentask_status s ON t.status_id = s.status_id
ORDER BY t.expires DESC
In my thread based messaging system, the table schema is
> messages table
id(int auto incr primary key)
body(varchar)
time(datetime)
>message_reference table
id(int auto incr primary key)
message_id(forgain key from message table)
sender
receiver
Here, I want to select the first message id which is sent to a new receiver and sender is the user who is logged in.
Doing this with multiple queries and some code is obviously possible but can it be done with a single query for performance issues??
You can try
EDIT:
If the id is auto increment, then the id will also increase with time and you can use:
SELECT message_reference.message_id, message_reference.receiver, messages.body
FROM message_reference, messages
WHERE message_reference.message_id IN (SELECT MIN(message_reference.message_id)
FROM message_reference
GROUP BY message_reference.receiver)
AND message_reference.message_id = messages.id AND message_reference.sender = <sender>
Here's my best guess as to what you want, but it would be easier if you gave known inputs, example data, and expected output.
SELECT
MR2.message_id
FROM (
SELECT
MR.sender,
MR.receiver,
M.MIN(`time`) AS min_time
FROM
Message_References MR -- Either use plural names (my personal preference) or singular, but don't mix them
INNER JOIN Messages M ON
M.id = MR.message_id
WHERE
MR.sender = <sender>
GROUP BY
MR.received) SQ
INNER JOIN Message_References MR2 ON
MR2.sender = SQ.sender AND
MR2.receiver = SQ.receiver AND
MR2.`time` = SQ.min_time
select mr.message_id from
message_reference as mr inner join
(select mr1.reciever max(m1.time) as time from messages as m1
inner join message_reference as mr1 on mr1.message_id = m1.id
group by mr1.reciever) as last
on mr.reciever = last.reciever and mr.time = last.time
join message reference with "maxtime per reciever" table on reciever and time
Well I got the answer, Just a group by query worked the way I wanted. I used query
SELECT SENDER,
RECEIVER,
BODY,
TIME,
MESSAGE_ID
FROM MESSAGE_REF JOIN MESSAGE
ON MESSAGE.ID=MESSAGE_REF.MESSAGE_ID
ORDER BY 'TIME' GROUP BY RECEIVER`
Thanks everyone for the help.