Mysql select query for getting co-workers - mysql

I have a many to many relationship between some Jobs and some Workers.
Each worker has a property like age. I want to get all the Jobs and Workers that collaborate with the workers of age 22 (for example), including the workers of age 22.
For example if A and B are two workers who do the Job X and one of them is 22 years old, I want a query to return both A and B (joined with the X and its properties)
I have three tables:
Job
1 JobI
2 JobII
Workers:
A Smith 22
B John 21
C Jack 23
J-W relation
1 A
1 B
2 B
2 C
In this example I want A and B info and Job I because A is 22 years old and collaborate with B in Job I

Something like
Select * From Workers
join (Select Distinct WorkerID From WorkerJobs Join Workers on Worker.WorkerID = WorkerJobs.WorkerID and Worker.Age = 22) worker22 on worker22.workerid = worker.workerid
join Jobs on jobs.jobid = workerjobs.jobid
join WorkerJobs on Workerjobs.workerid = workers.workerid
and WorkerJobs.JobId = Jobs.JobID
Ie get all the jobs with a 22 year old worker, then join back to jobs and workers to get the details.
Any 22 year old with more than one job will repeat as will any job with more than one 2 year old worker though.

Your question is a bit confusing.. Do you want all jobs for workers of age 22 or want to return A and B? Still I will try to answer both.
Lets say in your jobs table you have job_id,worker_id,job_description.... and lets say in your worker table you have worker_id,age,other description
In order to get all the jobs and workers with age 22 run following query.
SELECT jobs.*,workers.* FROM jobs,workers WHERE jobs.worker_id = workers.worker_id AND workers.age=22;
This will return all the jobs data and workers data associated with workers with age 22.
Hope this answers your question

Assuming your schema looks like this:
Table workers {
id,
age,
...
}
Table jobs {
id,
worker_id,
...
}
To answer your question, you need a query with a subquery.
The inner query
select jobs.id
from jobs
left join workers on workers.id = jobs.worker_id
where age = 22
returns all the jobs, who have workers aged 22.
The outer query
select *
from jobs, workers
where jobs.worker_id = workers.id
and jobs.id in (INNER QUERY)
selects all the jobs and workers, who have a job in the inner query.
The end result:
select *
from jobs, workers
where jobs.worker_id = workers.id
and jobs.id in (select jobs.id
from jobs
left join workers on workers.id = jobs.worker_id
where age = 22)

Related

Finding contradiction in mysql table

I have a table of 5000 rows with 9 columns in it. And I am in a process of data cleaning. So I need a query to return only rockets names that are Active and Retired at the same time
Below is a sample of 2 columns that I am working on :
Rocket
Status
Sputnik
Retired
Sputnik
Active
Vanguard
Retired
Juno I
Retired
Sputnik
Retired
Vostok
Retired
So the result should be like this :
Rocket
Status
Sputnik
Retired
Sputnik
Active
I tried distinct, self join, group by but I failed to achieve my goal.
-- This query will return every distinct rows:
select distinct(concat(rocket,'_', rocketstatus)) as BB
from space.test_1
group by bb
-- This query will return nothing:
select a.rocket, a.rocketstatus from space.test_1 b
join space.test_1 a on a.id = b.id
where a.rocketstatus not in (select b.rocketstatus from space.test_1 b)
May be this variant will suit you
select distinct a.Rocket,b.Status from
(
select Rocket,count(distinct Status) as cnt from test_1 group by Rocket
) a inner join test_1 b on b.Rocket=a.Rocket where a.cnt>1

SQL Counting Calls from other tables

Having trouble counting from a separate table. I'm only getting how many callers are making calls rather than each individual count for every call.
I have went in and checked that most callers make multiple calls but i'm not sure how to show this.
I'm looking for which Company has >18 calls.
Tables are:
Customer
Company_ref
Company_name
Contact_id
Address_1
Address_2
Caller
Caller_id
Company_ref
First_name
Last_name
Issue
Call_ref
Caller_id
Call_date
Detail
Query:
SELECT Company_name, Count(Call_ref)
from Customer JOIN Issue on (Contact_id = Caller_id)
Group by Company_name
and example of the outcome is
Affright Retail 5
Askew Inc. 5
Askew Shipping 6
Bai Services 2
Cell Group 5
Comfiture Traders 5
which is only counting how many callers rather than how many calls made
This should work (MS SQL-Server):
select a.Company_ref, count(c.Call_ref) as Calls from caller a
join Issue b on (a.Caller_id = b.Caller_id)
join Customer c on (a.Company_ref = c.Company_ref)
group by a.Company_ref
adding a Where clause to determine companies with 18 or more calls:
select * from (
select a.Company_ref, count(c.Call_ref) as Calls from caller a
join Issue b on (a.Caller_id = b.Caller_id)
join Customer c on (a.Company_ref = c.Company_ref)
group by a.Company_ref ) result
where Calls > 18
CallerID refers to Caller table not Customer table
SELECT Y.Company_name, Count(I.Call_ref)
FROM Issue I
JOIN Customer C
ON I.Caller_id = C.Caller_id
JOIN Company Y
ON C.Company_ref = Y.Company_ref
Group by Company_name

Loop through column and assign 0/1 MySQL

I have a MySQL database on consumers attending events. The database contains a users table, events table and checkins table which are all connected. But the database only contains info about users going to a certain event.
I want a query that loops through a couple of events and checks if a user went to one of them, and gives as a result:
Preffered result
I've tried with the following query:
select attend.idperson, attend.idmeeting,
(select case when
attend.idmeeting = 2901 or
attend.idmeeting = 9044 or
attend.idmeeting = 9161 or
attend.idmeeting = 2626
then 1 else 0 end) as attended
from attend
join meetings on attend.idmeeting = meetings.idmeeting
join persons on attend.idperson = persons.id
where meetings.verified = 1;
But this brings as a result all meetings where the persons actually went, and assigns a 1 if one of the meetings in the select case when query was attended and a 0 for the rest. The goal is to predict attendance using logistic regression, and this solution makes all further user data biased.
You could build a list of all people and meetings, then left join the attendance details:
select distinct a1.*,
case
when attend.idperson is null then 0
else 1
end as attended
from
(
select meetings.idmeeting, persons.id as p_id
from meetings
cross join persons
where meetings.verified = 1
) a1
left join attend
on attend.idmeeting = a1.idmeetings
and attend.personid a1.p_id

Mysql Multiple ANDS

I have three tables persons, jobs, jobs_persons
One person can have multiple jobs.
Person 1 is Technical Support AND Manager
Person 2 is Technical Support
Person 3 Is Manager
Job 1 Technical Support
Job 2 Manager
I need to find a query give me the result for the person who currently is Technical Support AND Manager
The answer would be only Person 1
SELECT persons.*
FROM persons INNER JOIN jobs_persons ON persons.id = jobs_persons.person_id
INNER JOIN jobs ON jobs.id = jobs_persons.job_id
WHERE job.id IN (1,2)
Returns 3 rows
SELECT persons.*
FROM persons INNER JOIN jobs_persons ON persons.id = jobs_persons.person_id
INNER JOIN jobs ON jobs.id = jobs_persons.job_id
WHERE job.id = 1 AND job.id = 2
Returns 0 rows.
I'm currently working on Ruby on Rails.
Somebody can help?
You want to use an OR operator. Using job.id = 1 AND job.id = 2 will only return elements where id equals 1 and at the same time 2. No element can do that. You want elemets where th id is 1 or where the id is 2.
to make it more obvious:
SELECT * FROM table WHERE lastname = 'Smith' AND firstname = 'James';
when executing this you obviously don't want everybody who is called Smith or James. ;-)
EDIT:
Misread the question. what you need is a second join to join the jobs table two times in and join them with the different jobs. It is a bit hard as you didn't show the schema, but this might work:
SELECT persons.*
FROM persons
INNER JOIN jobs_persons jp1 ON persons.id = jp1.person_id
INNER JOIN jobs_persons jp2 ON persons.id = jp2.person_id
INNER JOIN jobs j1 ON j1.id = jp1.job_id
INNER JOIN jobs j2 ON j2.id = jp2.job_id
WHERE j1.id = 1 AND j2.id = 2
Try this to get all the person who has got a job of 1 AND 2 in your associative entity table. No need to hit the job table.
SELECT p.*
FROM persons p
WHERE id in (
SELECT person_id FROM jobs_persons
WHERE job_id IN (1,2)
GROUP BY person_id
HAVING COUNT(*) = 2
);
With your recent comments, it seems you're having performance problems. That's really outside of the scope of this question and answer.
You need to make sure your indexes are in place on the appropriate columns:
jobs_person.job_id
persons.id

Grouping, counting and excluding based on column value

Although I've not a complete newbie in SQL or MySQL I notice that there's still quite a bit to learn. I cannot get my head around this one, after much trying, reading and searching. If you can give any pointers, I'd be grateful.
I have simplified the actual data and tables to the following.
Two tables are relevant: Staff, and Work. They contain data on staff in various projects.
Staff:
ID Name Unit
1 Smith Chicago
2 Clarke London
3 Hess Chicago
Work:
StaffID ProjectID
1 10
2 10
3 10
1 20
2 30
3 40
1 50
3 50
Goal:
To get grouped all those projects where there are staff from Chicago, with the count of all staff in that project.
Expected result:
Project Staff count
10 3
20 1
40 1
50 2
So the project 30 is not listed because its member(s) are not from Chicago.
My query below is obviously wrong. It counts only those project members who are from Chicago, not the whole project staff.
SELECT
work.projectID as Project, COUNT(*) as "Staff count"
FROM
staff
JOIN
work ON staff.ID=work.staffID
WHERE
unit="Chicago"
GROUP BY
work.projectID;
I'd put the test for Chicago in a subselect.
Alternatively you can use a self-join, but I find the sub-select easier to understand.
SELECT
w.projectid as project
,COUNT(*) as `staff count`
FROM work w
INNER JOIN staff s ON (w.staffID = s.id)
WHERE w.projectID IN (
SELECT w2.projectID FROM work w2
INNER JOIN staff s2 ON (w2.staffID = s2.id AND s2.unit = 'Chicago'))
GROUP BY w.projectid
Remove the where clause and add a having clause which checks that at least one member of staff is from Chicago.
SELECT
work.projectID as Project, COUNT(*) as "Staff count"
FROM
staff
JOIN
work ON staff.ID=work.staffID
GROUP BY
work.projectID
HAVING
count(case unit when 'Chicago' then 1 end) > 0;
Finally: the result. Thanks again both #Johan and #a'r for your help, and #Johan for getting me on the right track (in my case).
I changed the sub-select to a derived table, and inner-joined this with the Work table on projectID.
SELECT
w.projectID AS project
,COUNT(*) AS `staff count`
FROM work w
INNER JOIN
(SELECT DISTINCT w2.projectID
FROM work w2
INNER JOIN staff s ON (w2.staffID = s.id AND s.unit = 'Chicago')) c
ON (w.projectID = c.projectID)
GROUP BY w.projectID