Find common employees between departments - mysql

I'm using MySQL. I have a table called works(EID,DID,PCT_TIME) and PCT_TIME is not used here.
The question I have is: Find the two departments ( represented by DID) who have the highest number of employees ( he's represented by EID) in common.
I've tried that:
select count(*) as max_NBR_COMMUN from (select EID from WORKS group by EID having count(EID) >= 2) as temp
to get the number of employees common to two departments but it doesn't work.
EDIT: I've seen your answer and I thank you all, I'm a business student so not familiar with computer science and therefore sql.
So my final request is
select count(distinct wa.eid) as num_eids_in_common, wa.did, wb.did
from works wa
join works wb on wa.eid = wb.eid and wa.did < wb.did
group by wa.did, wb.did
order by num_eids_in_common desc
limit 1

Let's start with this.
create table works ( eid int not null, did int not null );
insert into works values (1,1), (1,1), (1,2), (1,3), (2,1), (2,2), (3,1), (4,4);
select * from works order by eid;
eid did
---------- ----------
1 1
1 1
1 2
1 3
2 1
2 2
3 1
4 4
Note that employee 1 has multiple entries in department 1, a curve ball.
To find out which employees are in more than one department we need to join works with itself, a self-join. This is like any other join, but table aliases are mandatory.
select wa.eid, wa.did, wb.did
from works wa
join works wb on wa.eid = wb.eid
and wa.did != wb.did;
This joins with any row that has the same employee ID but different department ID, because we don't want to see employees in our own departments.
eid did did
---------- ---------- ----------
1 1 2
1 1 3
1 1 2
1 1 3
1 2 1
1 2 1
1 2 3
1 3 1
1 3 1
1 3 2
2 1 2
2 2 1
Employee 1 shows up multiples times because it has multiple entries in works, remember the curve ball? We can remove these duplicates by selecting only the distinct rows.
select distinct wa.eid, wa.did, wb.did
from works wa
join works wb on wa.eid = wb.eid
and wa.did != wb.did;
eid did did
---------- ---------- ----------
1 1 2
1 1 3
1 2 1
1 2 3
1 3 1
1 3 2
2 1 2
2 2 1
We can also avoid counting each department pair twice by joining with wa.did < wb.did instead of wa.did != wb.did.
select distinct wa.eid, wa.did, wb.did
from works wa
join works wb on wa.eid = wb.eid
and wa.did < wb.did;
eid did did
---------- ---------- ----------
1 1 2
1 1 3
1 2 3
2 1 2
Now we have a list of all the employees who are in more than one department, and their departments.
We get the number of employees in common by grouping by both department IDs and counting the employees.
select count(distinct wa.eid) as num_eids_in_common,
wa.did, wb.did
from works wa
join works wb on wa.eid = wb.eid
and wa.did < wb.did
group by wa.did, wb.did;
num_eids_in_common did did
------------------ ---------- ----------
1 1 3
1 2 3
2 1 2
Finally we get the one with the most in common by sorting num_eids_in_common in descending order and limiting it to 1 row.
select count(distinct wa.eid) as num_eids_in_common,
wa.did, wb.did
from works wa
join works wb on wa.eid = wb.eid
and wa.did < wb.did
group by wa.did, wb.did
order by num_eids_in_common desc
limit 1;
num_eids_in_common did did
------------------ ---------- ----------
2 1 2

Related

get count(*) from multiple tables sql

I have three tables.
entry
ID title
1 Entry1
2 Entry2
3 Entry3
4 Entry4
user_likes
ID user_id entry_id
1 1 3
2 3 1
3 9 4
4 2 2
user_bookmarks
ID user_id entry_id
1 6 3
2 4 3
3 2 1
4 2 2
What i want is the sum of likes and bookmarks for each entry.
result
entryID likes bookmarks
1 1 1
2 1 1
3 1 2
4 1 0
Also with total sum of likes and bookmarks of each entry.
result2
entryID likes+bookmarks
1 2
2 2
3 3
4 1
I managed to get likes and bookmark result using this query in seperate tables. I was not able to show them together in a single table.
SELECT entry.id, COUNT(entry.id) AS likes FROM entry
INNER JOIN user_like ON user_like.entry_id = entry.id GROUP BY entry.id ORDER BY likes DESC
You should aggregate before joining:
select e.*, coalesce(l.likes, 0) as likes,
coalesce(b.bookmarks, 0) as bookmarks,
(coalesce(l.likes, 0) + coalesce(b.bookmarks, 0)) as both
from entries e left join
(select entryid, count(*) as likes
from likes l
group by entryid
) l
on l.entryid = e.id left join
(select entryid, count(*) as bookmarks
from bookmarks
group by entryid
) b
on b.entryid = e.id;

Mysql Group by counting issue

Database structure
Table 'applicants'
id org_id team_id
1 1 1
Table 'teams'
id name
1 Test
Table 'teams_members'
id team_id user_id
1 1 1
2 1 2
Table 'users_playeraccounts'
id user_id summoner_id rank_solo
1 1 1 5
2 1 2 8
3 2 3 7
select sum(rank_solo) as rank_sum,
max(rank_solo) as highest_rank,
count(tt.id) as members,
t.name,
o.team_id
from applicants o
join teams t on o.team_id = t.id
join teams_members tt on t.id = tt.team_id
join users_playeraccounts p on tt.user_id = p.user_id
where org_id = :org
group by team_id
This offcourse gives me a result like
rank_sum highest_rank members name team_id
20 8 3 Test 1
Is there a way for me to get both the count of members with their playeraccounts aka
If 1 user has 2 it'll be 2
And also a way for me to keep it as 1 so it literally just counts the rows found in teams_members neglecting the entries in users_playeraccounts?
I want to receive both 2 and 3 as a result of my query.
You want to count the distinct number of entries in tt.id, so you can do that like this:
SELECT ... COUNT(DISTINCT tt.id) AS distinct_members ...
Rather than giving you a count of every row that has a non-null tt.id, you'll get a count of the number of unique values.

Query: getting the last record for each member trouble cause by another value

i have data below for example
id product_id date
------ ---------- ----
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 2 2
7 3 1
result data query that i want "the last record of last date on each product_id"
to get it that result i use the query like below
SELECT a.* FROM test AS a
JOIN (SELECT MAX(id) AS id, product_id, MAX(DATE) AS DATE FROM test GROUP BY product_id) AS b
ON a.id = b.id AND a.product_id = b.product_id AND a.date = b.date
this time i got what i want as the result
id product_id date
------ ---------- --------
3 1 3
6 2 2
7 3 1
my problem when i add another data like below
id product_id date
------ ---------- --------
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 2 2
7 3 1
8 1 3
9 1 2
and use the same query the result become like this
id product_id date
------ ---------- --------
6 2 2
7 3 1
where the the value '1' for product_id?
Try this
SELECT id, product_id, DATE FROM test sitem WHERE product_id IN (1,2,3) AND DATE = (SELECT DATE FROM test WHERE product_id =
sitem.product_id ORDER BY DATE DESC LIMIT 1) AND id =
(SELECT id FROM test WHERE product_id = sitem.product_id ORDER BY DATE DESC,
id DESC LIMIT 1) GROUP BY product_id
This is your subquery:
SELECT MAX(id) AS id, product_id, MAX(DATE) AS DATE
FROM test
GROUP BY product_id
It is independently calculating the maximum of id and date. But, there is no guarantee that these two values are in the same record. There are ways to fix the subquery, but they are rather complicated.
Instead, I would suggest using an alternative method to get the last record:
SELECT t.*
FROM test t
WHERE NOT EXISTS (SELECT 1
FROM test t2
WHERE t2.product_id = t.product_id AND
(t2.date > t.date OR
t2.date = t.date AND t2.id > t.id
);
This identifies the last record for each product as the one where no other record has a larger date. And, if two records have the same date, no other record has a larger id.

Update Duplicate column values based on Count in MySQl

I Have a Table like this
Employeeid Name CompanyID
1 Achal 1
2 Anil 1
3 Anil 1
4 Sachi 2
5 Anil 2
6 Sachi 1
7 Sachi 2
I want to update the names of the employee if multiple employees are there in a same company
My resultant table should be like this
Employeeid Name CompanyID
1 Achal 1
2 Anil(1) 1
3 Anil(2) 1
4 Sachi(1) 2
5 Anil 2
6 Sachi 1
7 Sachi(2) 2
My query is something like this
Update tblemplayee emp
join
(
select sname,count(*)
from tblemployee
group by sname,companyid
) innertable
on innertable.employeeid=emp.employeeid
set sname = concat(sname,'(', ,')') .
How can i change my query to get the result.
If you need to execute your query only once, you could use this query:
UPDATE
employees INNER JOIN (
SELECT e1.Employeeid, COUNT(e2.Employeeid) n
FROM
employees e1 INNER JOIN employees e2
ON e1.Name=e2.Name
AND e1.CompanyID=e2.CompanyID
AND e1.Employeeid>=e2.Employeeid
INNER JOIN (SELECT Name, CompanyID
FROM employees
GROUP BY Name, CompanyID
HAVING COUNT(*)>1) dup
ON e1.Name=dup.Name AND e1.CompanyID=dup.CompanyID
GROUP BY
e1.Employeeid, e1.Name) counts
ON employees.Employeeid = counts.Employeeid
SET
Name = CONCAT(Name, '(', counts.n, ')');
Please see fiddle here.

first item used by a user

I am writing a query to grab the items that a specific user_id was the first to use. Here is some sample data -
item_id used_user_id date_used
1 1 2012-08-25
1 2 2012-08-26
1 3 2012-08-27
2 2 2012-08-27
3 1 2012-08-27
4 1 2012-08-21
4 3 2012-08-24
5 3 2012-08-23
query
select item_id as inner_item_id, ( select used_user_id
from test
where test.item_id = inner_item_id
order by date_used asc
limit 1 ) as first_to_use_it
from test
where used_user_id = 1
group by item_id
It returns the correct values
inner_item_id first_to_use_it
1 1
3 1
4 1
but the query is VERY slow on a giant table. Is there a certain index that I can use or a better query that I can write?
i can't get exactly what you mean because in your inner query you have sorted it by their used_user_id and and on your outer query you have filtered it also by their userid. Why not do this directly?
SELECT DISTINCT item_id AS inner_item_id,
used_user_id AS first_to_use_it
FROM test
WHERE used_user_id = 1
UPDATE 1
SELECT b.item_id,
b.used_user_id AS first_to_use_it
FROM
(
SELECT item_ID, MIN(date_used) minDate
FROM tableName
GROUP BY item_ID
) a
INNER JOIN tableName b
ON a.item_ID = b.item_ID AND
a.minDate = b.date_used
WHERE b.used_user_id = 1