I am fairly new to MySQL and I am having a bit of a problem trying to combine a few queries into a single one. Basically I have two tables:
I need to get:
ALL IDJobs where StaffID is NOT Part of it
ALL IDJobs where StaffID is part of it AND has a Status 1 or 6
.
Jobs
------------------
IDJob - The PKey
JobInfo - Some Data
JobPosition
------------------
PositionID - Each Job can have multiple positions
JobID - Value from Jobs Table
StaffID - Value from Staffs Table
Status - Status of Staff for the Job
I am trying to get all IDJobs WHERE
(
SELECT JobID AS IDJob
FROM SelectedStaff
WHERE StaffID <>10
)
UNION
(
SELECT IDJob
FROM Jobs
WHERE IDJob
IN (
SELECT JobID
FROM SelectedStaff
WHERE SelectStatus
IN ( 1, 6 )
AND StaffID =10
)
)
But the result is not returning for me the Job IDs where the Staff is not part of it. That would be the bigger list, and then filtering it with the smaller query.
Any help would be appreciated.
EDIT:
Sample data would be:
Jobs Table
IDJob JobInfo
1 Job1
2 Job2
3 Job3
.
JobPosition
PositionID JobID StaffID Status
1 2 10 0
2 2 10 6
3 3 10 0
This should result:
IDJob
1
2
Is this what you want?
select jp.JobId
from JobPosition jp
group by jp.JobId
having sum(StaffId = 10) = 0 or -- Staff10 is not part of the job
sum(StaffId = 10 and status in (1, 6)) > 0
This uses conditional aggregation in the where clause to count the number of rows that match each of your conditions.
So here is the solution that finally worked for me. I don't know if I am making it too complicated, but it is the right result:
(
SELECT IDJob
FROM Jobs
WHERE IDJob
NOT IN (
SELECT JobID AS IDJob
FROM JobPosition
WHERE StaffID = 10
)
)
UNION
(
SELECT IDJob
FROM Jobs
WHERE IDJob
IN (
SELECT JobID
FROM SelectedStaff
WHERE JobPosition IN (1,6)
AND StaffID=10
)
)
Related
I have a table called stages like this:
stageID
stage
parentStageID
1
Stage1
NULL
2
Stage2
3
3
Substage1
1
4
Stage3
2
The parentStageID references the stageID of its parent in the same table. I'm trying to write a query that selects everything in the table and sorts them by order of the next child in line. The NULL parentStageID being the first in the sequence, followed by the next stage with parentStageID equal to the last stageID.
The ordered table results like this:
stageID
stage
parentStageID
1
Stage1
NULL
3
Substage1
1
2
Stage2
3
4
Stage3
2
I'm not entirely sure how to go about doing this, but from other similar stack posts I was trying to do this with:
SELECT * FROM stages ORDER BY COALESCE(`parentStageID`, `stageID`), `parentStageID` IS NOT NULL, `stageID`;
Here I have this small Demo on SQL fiddle
as you can see this query is resulting as:
stageID
stage
parentStageID
1
Stage1
NULL
3
Substage1
1
4
Stage3
2
2
Stage2
3
Appreciate any ideas on the type of query I need for this!
You can use a recursive cte:
with recursive d(id, stage, pid) as (
select * from demo where parentstageid is null
union all
select d2.* from d d1 join demo d2 on d1.id = d2.parentstageid
)
select * from d;
Output:
id
stage
pid
1
Stage1
null
3
Substage1
1
2
Stage2
3
4
Stage3
2
Hi this is quite a tricky question, your data is similar to a companies employee data we can say for example:
Employee 1 has Employee 3 as his higher up
Employee 3 is the highest level in company
Employee 2 has Employee 1 as his higher up
what you need is to order employee based on their level in company, highest first then level below it and so on
Employee 3
Employee 1 , Employee 3
Employee 2 , Employee 1
Considering this above scenario, I tried to create a T-SQL code hope it helps:
-- Getting all data in seprate table
-- Indi column added to tell if that record is processed or not for ordering
-- Ord column added to give order for final output
select *,ParentStageid as dummy, 0 ord, 0 indi
into #test
from stage
Declare #pstageID int = 0
Declare #order int = 1
-- while loop which will run through each record
while exists(select * from #test where indi = 0)
begin
update #test
set ord = #order, indi = 1 ,#pstageID = stageID
where dummy is null and indi = 0
Update #test
set dummy = null
where parentStageID = #pstageID
set #order = 1 + #order
end
-- Final Output as asked
select * from #test
order by ord
Output:
This code might not be best for huge data, but it will give the expected output.
I have a database with the following tables: Students, Classes, link_student_class. Where Students contains the information about the registered students and classes contains the information about the classes. As every student can attend multiple classes and every class can be attended by multiple students, I added a linking-table, for the mapping between students and classes.
Linking-Table
id | student_id | class_id
1 1 1
2 1 2
3 2 1
4 3 3
In this table both student_id as well as class_id will appear multiple times!
What I am looking for, is a SQL-Query that returns the information about all students (like in 'SELECT * FROM students') that are not attending a certain class (given by its id).
I tried the following SQL-query
SELECT * FROM `students`
LEFT JOIN(
SELECT * FROM link_student_class
WHERE class_id = $class_id
)
link_student_class ON link_student_class.student_id = students.student_id
Where $class_id is the id of the class which students i want to exclude.
In the returned object the students i want to include and those i want to exclude are different in the value of the column 'class_id'.
Those to be included have the value 'NULL' whereas those I want to exclude have a numerical value.
NOT EXISTS comes to mind:
select s.*
from students s
where not exists (select 1
from link_student_class lsc
where lsc.student_id = s.student_id and
lsc.class_id = ?
);
The ? is a placeholder for the parameter that provides the class.
you should check for NULL link_student_class.student_id
SELECT *
FROM `students`
LEFT JOIN(
SELECT *
FROM link_student_class
WHERE class_id = $class_id
) link_student_class ON link_student_class.student_id = students.student_id
where link_student_class.student_id is null
Or also a NOT IN predicate:
WITH
stud_class(id,stud_id,class_id) AS (
SELECT 1, 1,1
UNION ALL SELECT 2, 1,2
UNION ALL SELECT 3, 2,1
UNION ALL SELECT 4, 3,3
)
,
stud(stud_id,fname,lname) AS (
SELECT 1,'Arthur','Dent'
UNION ALL SELECT 2,'Ford','Prefect'
UNION ALL SELECT 3,'Tricia','McMillan'
UNION ALL SELECT 4,'Zaphod','Beeblebrox'
)
SELECT
s.*
FROM stud s
WHERE stud_id NOT IN (
SELECT
stud_id
FROM stud_class
WHERE class_id= 2
);
-- out stud_id | fname | lname
-- out ---------+--------+------------
-- out 3 | Tricia | McMillan
-- out 4 | Zaphod | Beeblebrox
-- out 2 | Ford | Prefect
-- out (3 rows)
-- out
-- out Time: First fetch (3 rows): 9.516 ms. All rows formatted: 9.550 ms
I'm having trouble with a query. I have 4 tables
first table: person
ID_No
-----
1
2
3
second table: update_general_details
Update_ID ID_No Email Mob_No
--------- ----- -------------- --------
1 1 some#gmail.com 078231231
third table: update_training
Training_ID ID_No Training_Name Training-Date
----------- ---- ------------- -------------
1 2 Mysql training 2014-09-09
third table: update_award
Award_ID ID_No Award_Name Award_Year
-------- ----- ----------- ----------
1 1 Best in Math 2010
What I am trying to do is to select distinct ID numbers where the ID number could contain in the second table or third or fourth.
Desired result:
ID_No
1
2
Here is my code:
Select DISTINCT person.ID_No,
from update_award, update_general, update_training, person
where EXISTS (SELECT update_award.ID_No
FROM update_award, person
WHERE person.ID_No = update_award.ID_No) or
EXISTS (SELECT update_training.ID_No
FROM update_training, person
WHERE person.ID_No = update_training.ID_No) or
EXISTS (SELECT update_general_details.ID_No
FROM update_general, person
WHERE person.ID_No = update_general.ID_No)
this query returns nothing. Thank you in advance
Please remove the detail tables from the main query and the person table from the subqueries, that should help a lot:
Select person.ID_No
from person
where EXISTS (
SELECT 1
FROM update_award
WHERE person.ID_No = update_award.ID_No
)
or EXISTS (
SELECT 1
FROM update_training
WHERE person.ID_No = update_training.ID_No
) or EXISTS (
SELECT 1
FROM update_general
WHERE person.ID_No = update_general.ID_No
);
If the only thing you need is the ID, you can skip the person table, and just query the other three directly. Using union will remove any duplicates:
SELECT update_award.ID_No
FROM update_award
UNION
SELECT update_training.ID_No
FROM update_training
UNION
SELECT update_general_details.ID_No
FROM update_general
I have the following table stops how can I check whether the following stops name order GHI, JKL, MNO is available in my stops table?
stops table:
CREATE TABLE IF NOT EXISTS stops
(
stop_id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
name varchar(30) NOT NULL,
lat double(10,6),
longi double(10,6)
);
Simple:
1 ABC
2 DEF
3 GHI
4 JKL
5 MNO
6 PQR
7 SDU
8 VWX
This query will return 1 when there is an ordered of 'GHI','JKL','MNO':
SELECT 1
FROM stops s1
JOIN stops s2 ON s1.stop_id = s2.stop_id - 1
JOIN stops s3 ON s2.stop_id = s3.stop_id - 1
WHERE CONCAT(s1.name, s2.name, s3.name) = CONCAT('GHI','JKL','MNO')
SQL Fiddle Demo
This is a variation of the well known "find equal sets" task.
You need to insert the searched route into a table with a sequenced stop_id:
create table my_stops(stop_id INT NOT NULL,
name varchar(30) NOT NULL);
insert into my_stops (stop_id, name)
values (1, 'GHI'),(2, 'JKL'),(3, 'MNO');
Then you join and calculate the difference between both sequences. This returns a totally meaningless number, but always the same for consecutive values:
select s.*, s.stop_id - ms.stop_id
from stops as s join my_stops as ms
on s.name = ms.name
order by s.stop_id;
Now group by that meaningless number and search for a count equal to the number of searched steps:
select min(s.stop_id), max(s.stop_id)
from stops as s join my_stops as ms
on s.name = ms.name
group by s.stop_id - ms.stop_id
having count(*) = (select count(*) from my_stops)
See Fiddle
Another alternative:
select 1
from stops x
where x.name = 'GHI'
and (select GROUP_CONCAT(name order by y.stop_id)
from stops y where y.stop_id between x.stop_id + 1
and x.stop_id + 2
) = 'JKL,MNO';
I have a Table that tracks followers
FollowerUserId, FollowingUserId
1 2
2 1
3 1
4 1
1 5
I want to get all user that given Id follows and is followed by or Both.
for example for UserId 1,I want result to be: (FG: Following, FD: Followed, B: Both ways)
2,B
5,FG
3,FD
4,FD
i can easily get FG and FD by doing union
Select FollowerUserId, 'FD' From Table Where FollowingUserId =1
Union
Select FollowingUserId, 'FG' From Table Where FollowerUserId =1;
with above i get user 2 as
2,FG
2,FD
from above but I really need 2,B without UserId 2 duplicated.
How can this be done efficiently?
You can use aggregation on your basic query:
SELECT UserId,
(CASE WHEN COUNT(DISTINCT which) = 1 THEN MIN(which)
ELSE 'B'
END)
FROM (Select FollowerUserId as UserId, 'FD' as which From Table Where FollowingUserId = 1
Union ALL
Select FollowingUserId, 'FG' From Table Where FollowerUserId = 1
) f
GROUP BY UserId;