Display all employees working on all of the projects? - mysql

table 1 includes employee name and their initials
table 2 includes projectnumber and pmember(initials as well)
we only have to display the name of the employees so i have to use a WHERE clause, which i can't construct :( here's what i've done so far. it only returns 1 employee (correct answer is 2 employees)
select t1.name
from t1
where t1.initials IN (select t2.pmember
from t2
having count(t2.projectnumber) > 1)
thanks in advance!

select t1.name
from t1
left join t2 on t1.initials = t2.pmember
group by t1.name
having sum(t2.projectnumber is null) = 0

This query should give you the names of the members working on all projects:
SELECT T1.NAME
FROM T1
JOIN T2 ON T1.INITIALS = T2.PMEMBER
GROUP BY T1.NAME
HAVING COUNT(T2.PROJECTNUMBER) = (SELECT COUNT(1) FROM T2 T2ALIAS)

Maybe this query helps you:
SELECT T1.NAME
FROM T1
INNER JOIN T2 ON T1.INITIALS = T2.PMEMBER
HAVING COUNT(T2.PROJECTNUMBER) > 1

To show all emp that works on all projects, you need a distinct count like this, I think:
SELECT NAME FROM T1 WHERE INITIALS IN (
SELECT PMEMBER FROM T2 HAVING DISTINCT COUNT(PROJECTNUMBER) = (
SELECT DISTINCT COUNT(PROJECTNUMBER) FROM T2)
GROUP BY PMEMBER)

Related

Select distinct pairs in SQL

For this table each column has distinct rows i.e count(Name) = count(Spouse_Name) = count(*)
Want to write a SQL query where pairs (Name and Spouse_Name) are distinct i.e Alex Sandra and Sandra Alex are same.
The output should be following:
Note: Self Inner Join if possible.
Untested:
select distinct t1.name, t1.spouse_name
from table t1
inner join table t2
on concat(t1.name, t1.spouse_name) = concat(t2.spouse_name, t2.name)
I couldn't find the table name in your post so I used the name table.
Assuming that name and spouse_name will never be equal in the same row you can use NOT EXISTS like this:
select t.*
from tablename t
where t.name < t.spouse_name
or not exists (
select 1 from tablename
where name = t.spouse_name and spouse_name = t.name
)
This code will work in any database since it uses standard SQL.
For MySql and this sample data you can do this self join:
select distinct
least(t1.name, t1.spouse_name) name,
greatest(t1.name, t1.spouse_name) spouse_name
from tablename t1 inner join tablename t2
on t1.name = t2.spouse_name and t2.name = t1.spouse_name
Although the same results can be obtained without a join:
select distinct
least(t1.name, t1.spouse_name) name,
greatest(t1.name, t1.spouse_name) spouse_name
from tablename t1
And another query with a self join:
select t1.name, t1.spouse_name
from tablename t1 inner join tablename t2
on t2.spouse_name = t1.name and t2.name = t1.spouse_name
where t1.name < t1.spouse_name

Get id of the record having Min() value

I have a complex mysql query where one of the Select fields is Min(value). Since all the 'values' are unique, is there also a way to get found min value's row id along?
In other words if we simplify the query to this question, it is like this:
SELECT t1.name, MIN(t2.value) AS minval
FROM table1 t1
LEFT JOIN table2 t2
ON t2.id_user = t1.id
GROUP BY id_user
How can i now know which t2.id was chosen for lowest t2.value for particular user? Thank you!
Use ROW_NUMBER() to find the first value of each id_user
You can replace * with the fields you need
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY t2.id_user ORDER BY t2.value) as rnk
FROM table1 t1
LEFT JOIN table2 t2
ON t2.id_user = t1.id
) as X
WHERE X.rnk = 1
Maybe this simple, dont know how complex your statement is:
SELECT name,value,id
FROM(
SELECT t1.name,t2.value,t2.id
FROM table1 t1
LEFT JOIN table2 t2
ON t2.id_user = t1.id
GROUP BY t2.id,id_user
ORDER BY t1.name,t2.id asc) as test
GROUP BY name;

Select from mysql table unique records according to a Field

I have a table in MySQL which I store registrations info.
I need to select all rows but only the latest according to email field and ID field
My table:
and I need
select *
from yourTablename
where (id,email) in
(select max(id),email from yourTablename group by email);
Another approach with Inner Join:(As suggested by Tim)
SELECT t1.*
FROM t t1
INNER JOIN
(
SELECT email, MAX(id) AS max_id
FROM t t2
GROUP BY email
) t2
ON t1.email = t2.email AND
t1.id = t2.max_id;
DEMO
Thanks for the replies.
Using
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT email, MAX(name) AS max_name
FROM yourTable
GROUP BY email
) t2
ON t1.email = t2.email AND
t1.name = t2.max_name;
Worked fine.
Thanks

SQL: full outer join (ambitious column name)

I have two table, t1 and t2.
-- t1
id name address
1 Tim A
2 Marta B
-- t2
id name address
1 Tim A
3 Katarina C
If I do t1 full outer join with t2
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
However, the result has ambitious id, name, address.
How do I rename this so that I don't have duplicate column name?
Attempt:
SELECT name, address FROM
(SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id) as derived_table;
return: ERROR- duplicate column name "name".
Ditch the * in the SELECT list.
Specify the list of expressions to be returned. And qualify all column references with either the table name, or preferably, a shorter table alias.
And assign an alias to the expression and that will be the name of the column in the resultset.
Also, the query shown is not equivalent to a FULL OUTER JOIN.
If the goal is return all rows from t1, and to also return rows from t2 where a matching row doesn't exist in t1, I'd do something like this...
SELECT t.id AS t_id
, t.name AS t_name
, t.addr AS t_addr
FROM t1 t
UNION ALL
SELECT s.id
, s.name
, s.addr
FROM t2 s
LEFT
JOIN t1 r
ON r.id = s.id
WHERE r.id IS NULL
Try fully qualifying it like
SELECT t1.id, t1.name, t1.address FROM t1

Joining three tables such that extra matches are discarded?

How can I write a query to give the results of three tables such that there's only one result per "line"?
The tables are:
T1 (ID, name, IP)
T2 (ID, date_joined)
T3 (ID, address, date_modified)
The relations are:
T1-T2 1:1, T1-T3 1:M - there can be many address rows per ID in T3.
What I want is a listing of all users with the fields above, but IF they have an address, I only want to record ONE (bonus would be if it is the latest one based on T3.date_modified).
So I should end up with exactly the number of records in T1 (happens to be equal to T2 in this case) and no more.
I tried:
select t.ID, t.name, t.IP, tt.ID, tt.date_joined, ttt.ID, ttt.address
from T1 t JOIN T2 tt ON (t.ID = tt.ID) JOIN T3 ttt ON (t.ID = ttt.ID)
And every sensible combination of LEFT, RIGHT, INNER, etc joins I could think of! I keep getting multiple duplicate because of T3
This query should work:
select
t1.ID, t1.name, t1.IP, t2.date_joined, t3x.address
from t1
join t2 on t1.ID = t2.id
left join (
select t3.*
from t3
join (
select id, max(date_modified) max_date
from t3
group by id
) max_t3 on t3.id = max_t3.id and t3.date_modified = max_t3.max_date
) t3x on t1.ID = t3x.id
First you do the normal join between t1 and t2 and then you left join with a derived table (t3x) that is the set of t3 rows having the latest date.
So T2 is actually not relevant here. You just need a way to join from T1 to T3 in a way that gets you at most one T3 row per T1 row.
One way of doing this would be:
select
T1.*,
(select address from T3 where T3.ID=T1.ID order by date_modified desc limit 1)
from T1;
This won't likely be very efficient, being a correlated subquery, but you may not care depending on the size of your dataset.
It's also only good for getting one column from T3, so if you had Address, City, and State, you'd have to figure out something else.
You can use sub query with Top 1 so that u get only one result from T3
here is a sample sql
select * into #T1 from(
select 1 ID
union select 2
union select 3) A
select * into #T2 from(
select 1 ID
union select 2
union select 3) A
select * into #T3 from(
select 1 ID, 'ABC' Address, getDate() dateModified
union select 1, 'DEF', getDate()
union select 3, 'GHI', getDate()) A
select *, (select top 1 Address from #T3 T3 where T3.ID= T1.ID order by datemodified desc) from #T1 T1
inner join #T2 T2 on T1.ID = T2.ID
Bonus :- you can also add order by dateModified desc to get the latest address