Order By on Select Query in Oracle - sql

I want to use query in Order By clause, is this possible... ?
select s.staff_list_pk, s.staff_name, Designation_fn(s.designation_fk)
Designation, s.bps, Department_fn(s.department_fk) Department
from staff_list s
where s.RESERVE = 'N' and s.INTEREST = 'I'
and s.bps in (18,19,20)
and s.department_fk in (select department_fk from perority_dept
where `et_blcok = 'Comp. Engg.')
and s.staff_list_pk not in (select staff_list_fk from SUPERINTENDENT)
order by (select perority from perority_dept where et_blcok = 'Comp. Engg.'), s.bps desc;

This should work. Please try once.
with xyz as (SELECT department_fk ,perority
FROM perority_dept
WHERE et_blcok = 'Comp. Engg.'),
klm as (select staff_list_fk
from SUPERINTENDENT)
SELECT s.staff_list_pk,
s.staff_name,
Designation_fn (s.designation_fk) Designation,
s.bps,
Department_fn (s.department_fk) Department
FROM staff_list s , xyz x ,klm k
WHERE s.RESERVE = 'N'
AND s.INTEREST = 'I'
AND s.bps IN (18, 19, 20)
AND s.department_fk = x.department_fk
and s.staff_list_pk <> k.staff_list_fk
order by xyz.perority,s.bps desc;

Related

SQL to select the 'first' date a project was made inactive for all projects

I am trying to work out the SQL I would need to select certain records, here is an example of what I'm trying to do:
Project number
Active/Inactive
Date
1
A
1/1/20
1
I
3/1/20
1
A
5/1/20
1
I
7/1/20
1
I
9/1/20
2
I
1/1/19
2
A
5/1/19
3
A
1/3/20
3
I
3/3/20
3
I
5/3/20
Note: A=Active project, I=Inactive.
What I would like to do is for each project where the project is currently inactive (i.e. the latest date for the project in the above table is set to I), return the row of the longest time ago it was made inactive, but NOT before it was last active (hope this is understandable!). So for the above table the following would be returned:
Project number
Active/Inactive
Date
1
I
7/1/20
3
I
3/3/20
So proj number 1 is inactive and the earliest time it was made inactive (after the last time it was active) is 7/1/20. Project 2 is not selected as it is currently active. Project 3 is inactive and the earliest time it was made inactive (after the last time it was active) is 3/3/20.
Thanks.
You could use the 'row_number' function to help you.
create TABLE #PROJECT(ProjectNumber int, [Status] varcha(1), [Date] date)
INSERT INTO #PROJECT VALUES
(1 ,'A' ,'1/1/20'),
(1 ,'I' ,'3/1/20'),
(1 ,'A' ,'5/1/20'),
(1 ,'I' ,'7/1/20'),
(1 ,'I' ,'9/1/20'),
(2 ,'I' ,'1/1/19'),
(2 ,'A' ,'5/1/19'),
(3 ,'A' ,'1/3/20'),
(3 ,'I' ,'3/3/20'),
(3 ,'I' ,'5/3/20')
select * from
(SELECT
row_number() over (partition by projectNumber order by [date]) as [index]
,*
FROM
#PROJECT
WHERE
[STATUS] = 'I'
) as a where [index] = 1
Using some effective date joins, this should work. I am using SQL Server. Create your tables and set up the same data set you provided:
CREATE TABLE dbo.PROJECTS
(
PROJ_NUM int NULL,
STTS char(1) NULL,
STTS_DT date NULL
) ON [PRIMARY]
GO
INSERT INTO dbo.PROJECTS values (1, 'A', '1/1/20');
INSERT INTO dbo.PROJECTS values (1, 'I', '3/1/20');
INSERT INTO dbo.PROJECTS values (1, 'A', '5/1/20');
INSERT INTO dbo.PROJECTS values (1, 'I', '7/1/20');
INSERT INTO dbo.PROJECTS values (1, 'I', '9/1/20');
INSERT INTO dbo.PROJECTS values (2, 'I', '1/1/19');
INSERT INTO dbo.PROJECTS values (2, 'A', '5/1/19');
INSERT INTO dbo.PROJECTS values (3, 'A', '1/3/20');
INSERT INTO dbo.PROJECTS values (3, 'I', '3/3/20');
INSERT INTO dbo.PROJECTS values (3, 'I', '5/3/20');
Write a sub-query that filters out just to the projects that are INACTIVE:
-- sub-query that gives you projects that are inactive
SELECT PROJ_NUM, STTS, STTS_DT FROM dbo.PROJECTS CURRSTTS
WHERE STTS_DT = (SELECT MAX(STTS_DT) FROM dbo.PROJECTS ALLP WHERE ALLP.PROJ_NUM = CURRSTTS.PROJ_NUM)
AND CURRSTTS.STTS = 'I'
;
Write another sub-query that provides you the last active status date for each project:
-- sub-query that gives you last active status date for each project
SELECT PROJ_NUM, STTS, STTS_DT FROM dbo.PROJECTS LASTACTV
WHERE STTS_DT = (SELECT MAX(STTS_DT) FROM dbo.PROJECTS ALLP WHERE ALLP.PROJ_NUM = LASTACTV.PROJ_NUM AND ALLP.STTS = 'A')
;
Combine those two sub-queries into a query that gives you the list of inactive projects with their last active status date:
-- sub-query using the 2 above to show only inactive projects with last active stts date
SELECT CURRSTTS.PROJ_NUM, CURRSTTS.STTS, CURRSTTS.STTS_DT, LASTACTV.STTS_DT AS LASTACTV_STTS_DT FROM dbo.PROJECTS CURRSTTS
INNER JOIN
(SELECT PROJ_NUM, STTS, STTS_DT FROM dbo.PROJECTS LASTACTV
WHERE STTS_DT = (SELECT MAX(STTS_DT) FROM dbo.PROJECTS ALLP WHERE ALLP.PROJ_NUM = LASTACTV.PROJ_NUM AND ALLP.STTS = 'A'))
LASTACTV ON CURRSTTS.PROJ_NUM = LASTACTV.PROJ_NUM
WHERE CURRSTTS.STTS_DT = (SELECT MAX(STTS_DT) FROM dbo.PROJECTS ALLP WHERE ALLP.PROJ_NUM = CURRSTTS.PROJ_NUM)
AND CURRSTTS.STTS = 'I'
Add one more layer to the query that selects the MIN(STTS_DT) that is greater than the LASTACTV_STTS_DT:
-- final query that uses above sub-query
SELECT P.PROJ_NUM, P.STTS, P.STTS_DT
FROM dbo.PROJECTS P
INNER JOIN (
SELECT CURRSTTS.PROJ_NUM, CURRSTTS.STTS, CURRSTTS.STTS_DT, LASTACTV.STTS_DT AS LASTACTV_STTS_DT FROM dbo.PROJECTS CURRSTTS
INNER JOIN
(SELECT PROJ_NUM, STTS, STTS_DT FROM dbo.PROJECTS LASTACTV
WHERE STTS_DT = (SELECT MAX(STTS_DT) FROM dbo.PROJECTS ALLP WHERE ALLP.PROJ_NUM = LASTACTV.PROJ_NUM AND ALLP.STTS = 'A'))
LASTACTV ON CURRSTTS.PROJ_NUM = LASTACTV.PROJ_NUM
WHERE CURRSTTS.STTS_DT = (SELECT MAX(STTS_DT) FROM dbo.PROJECTS ALLP WHERE ALLP.PROJ_NUM = CURRSTTS.PROJ_NUM)
AND CURRSTTS.STTS = 'I'
) SUB ON SUB.PROJ_NUM = P.PROJ_NUM
WHERE P.STTS_DT = (SELECT MIN(STTS_DT) FROM dbo.PROJECTS ALLP WHERE ALLP.PROJ_NUM = P.PROJ_NUM AND ALLP.STTS_DT > SUB.LASTACTV_STTS_DT)
The result I get back matches your desired result:
"Greatest n-per group" is the thing to look up when you run accross a problem like this again. Here is a query that will get what you need in postgresSQL.
I realized I changed your column to a boolean, but you will get the gist.
with most_recent_projects as (
select project_number, max(date) date from testtable group by project_number
),
currently_inactive_projects as (
select t.project_number, t.date from testtable t join most_recent_projects mrp on t.project_number = mrp.project_number and t.date = mrp.date where not t.active
),
last_active_date as (
select project_number, date from (
select t.project_number, rank() OVER (
PARTITION BY t.project_number
ORDER BY t.date DESC), t.date
from currently_inactive_projects cip join testtable t on t.project_number = cip.project_number where t.active) t1 where rank = 1
)
-- oldest inactive -- ie, result
select t.project_number, t.active, min(t.date) from last_active_date lad join testtable t on lad.project_number = t.project_number and t.date > lad.date group by t.project_number, t.active;
This is a variation of "gaps and islands" problem.
The query may be like this
SELECT
num,
status,
MIN(date) AS date
FROM (
SELECT
*,
MAX(group_id) OVER (PARTITION BY num) AS max_group_id
FROM (
SELECT
*,
SUM(CASE WHEN status = prev_status THEN 0 ELSE 1 END) OVER (PARTITION BY num ORDER BY date) AS group_id
FROM (
SELECT
*,
LAG(status) OVER (PARTITION BY num ORDER BY date) AS prev_status
FROM projects
) groups
) islands
) q
WHERE status = 'I' AND group_id = max_group_id
GROUP BY num, status
ORDER BY num
Another approach using CTEs
WITH last_status AS (
SELECT
*
FROM (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY num ORDER BY date DESC) AS rn
FROM projects
) rns
WHERE rn = 1
),
last_active AS (
SELECT
num,
MAX(date) AS date
FROM projects
WHERE status = 'A'
GROUP BY num
),
last_inactive AS (
SELECT
p.num,
MIN(p.date) AS date
FROM projects p
WHERE p.status = 'I'
AND (
EXISTS (
SELECT 1 FROM last_active la
WHERE la.num = p.num AND la.date < p.date
)
OR NOT EXISTS (
SELECT 1 FROM last_active la
WHERE la.num = p.num
)
)
GROUP BY num
)
SELECT
ls.num,
ls.status,
li.date
FROM last_status ls
JOIN last_inactive li ON li.num = ls.num
WHERE ls.status = 'I'
You can check a working demo with both queries here

Select only the records with same values

I am working on a SQL statement that will become a part of a view. What I need is to extract only the records that have the same unique key twice. The query looks like below right now.
select distinct
rscmaster_no_in, rsc_no_in, calendar_year, calendar_month,
Wstat_Abrv_Ch,
h.Wstat_no_in, Staffing_Calendar_Date, payhours,
l.OTStatus
from
vw_all_ts_hire h
left join
MCFRS_OTStatus_Lookup l on l.wstat_no_in = h.Wstat_no_in
where
rscmaster_no_in in (select rscmaster_no_in from vw_rsc_ECC_splty)
and Wstat_Abrv_Ch <> ''
and h.Wstat_no_in in (103, 107)
and l.OTStatus in ('ECCOTRemove', 'ECCOTSignup')
and Staffing_Calendar_Date = '2020-11-01' -- only for the testing purposes. Will be removed later.
order by
RscMaster_no_in
The result I get from the query above is:
I need to modify the SQL statement so that the end result is like below:
How can I modify the above statement to spit out the end result like that?
Use the analytic count(*) over () function.
with cte as (
select
count(*) over (partition by YourUniqueKey) as MyRowCount
{rest of your query}
)
select *
from cte
where MyRowCount = 2;
This should give you the results you want (performance is dependent on indexes/table design).
This takes your core logic and puts it into a sub select that only returns records that have a count > 1.
Then use those ID's to select all the data you need but only for those ID's that are in the sub select with count > 1
select distinct rscmaster_no_in,rsc_no_in, calendar_year, calendar_month,
Wstat_Abrv_Ch, h.Wstat_no_in, Staffing_Calendar_Date, payhours ,l.OTStatus
from vw_all_ts_hire h
left join MCFRS_OTStatus_Lookup l on l.wstat_no_in = h.Wstat_no_in
WHERE rscmaster_no_in IN (
SELECT rscmaster_no_in
from vw_all_ts_hire h
left join MCFRS_OTStatus_Lookup l on l.wstat_no_in = h.Wstat_no_in
where rscmaster_no_in in (select rscmaster_no_in from vw_rsc_ECC_splty)
and Wstat_Abrv_Ch <> ''
and h.Wstat_no_in in (103, 107)
and l.OTStatus in ('ECCOTRemove', 'ECCOTSignup')
and Staffing_Calendar_Date = '2020-11-01' -- only for the testing purposes. Will be removed later.
GROUP BY rscmaster_no_in
HAVING COUNT(*) > 1
)
order by RscMaster_no_in
You can use COUNT(*) OVER () window function such as
SELECT *
FROM
(
SELECT COUNT(*) OVER (PARTITION BY rscmaster_no_in) AS cnt,
t.*
FROM tab t
) t
WHERE cnt>1
AND OTStatus = 'ECCOTRemove'
This may help you :
select * from (
select distinct
rscmaster_no_in, rsc_no_in, calendar_year, calendar_month,
Wstat_Abrv_Ch,
h.Wstat_no_in, Staffing_Calendar_Date, payhours,
l.OTStatus,
SELECT COUNT(*) OVER (PARTITION BY rscmaster_no_in) AS uinqueCount
from
vw_all_ts_hire h
left join
MCFRS_OTStatus_Lookup l on l.wstat_no_in = h.Wstat_no_in
where
rscmaster_no_in in (select rscmaster_no_in from vw_rsc_ECC_splty)
and Wstat_Abrv_Ch <> ''
and h.Wstat_no_in in (103, 107)
and l.OTStatus in ('ECCOTRemove', 'ECCOTSignup')
and Staffing_Calendar_Date = '2020-11-01' -- only for the testing purposes. Will be removed later.
) innerReult
where uinqueCount=2 --Or uinqueCount>1 base on your business
order by
RscMaster_no_in

How to get passed and failed students using SQL?

I am trying to get those students who passed the first exams will be eligible for 2nd-month exams.
For example student_ID = 1 and Exam_ID = 1 pass then he will be eligible for the exams of Exam_ID = 2.
But the students failed in Exam_ID = 2 will not be eligible for exam_ID = 3 and passed students shouldn't be shown in Exam_ID = 2.
For exam2 entry only those students should show who passed exam1 and in exam2 will be showing for exam3 entry those who are failed in exam2. Mean the students who passed exam1 but fail in exam2.
I am confused what query will be work for this.
I tried this:
select student_Id
from Tbl_StudentsExamMarking
where Office_Id = 1
and Class_Id = 1
and Exam_Id = 1
and Status = 'Pass'
but I am getting only student_id=1 and 2 while student_id=2 passed the exam1 then he shouldn't be shown in exam1. I mean the students shouldn't show who passed the exam1 and students shouldn't show for exam2 who passed exam2.
on running query I am getting this result.
I tried to solve this problem. Kindly help me in this scenario.
Thanks.
You could join the table with itself and filter each join for the specific exam_id.
For example (You will need to replace #students with your table name):
In the following I make a subquery for exam_id = 1, a second subquery for exam_id = 2 and a third subquery for exam_id =3.
This gives you a "new table" that you then can filter.
SELECT
E1.studentid,
E1.Status AS [Status_exam2],
E2.Status AS Status_exam2,
E3.Status AS Status_exam3
FROM
(
-- The first exam_id as the main table as normally all students will do the first exam
SELECT *
FROM #students
Where exam_id = 1
) E1
LEFT JOIN
(
-- Left join with the second selection as maybe not all patients already did the
-- second exam
SELECT *
FROM #students
Where exam_id = 2
) E2 ON E1.studentid = E2.studentid
LEFT JOIN
(
SELECT *
FROM #students
Where exam_id = 3
) E3 ON E1.studentid = E3.studentid
With your example this gives the following output:
This "new" table, you can filter:
For example:
Patients passed exam_id1 but did not do the second or failed the second one
Add the following at the end of the above program:
WHERE E1.Status = 'Pass'
AND E2.Status is null or E2.Status = 'Fail'
This gives you the following:
You seem to be assuming that tests come in sequence and only depend on a single prerequisite. This isn't a recommended approach but is it the result that you need?
select Student_id, max(Exam_Id) as Last_Pass_Exam_Id
from Tbl_StudentsExamMarking
where Status = 'Passed'
group by Student_id
Assuming I'm understanding your challenge, try something like this:
-- Exam data mockup table and data.
DECLARE #ExamData TABLE ( Student_id INT, Class_id INT, Office_Id INT, Exam_Id INT, [Status] VARCHAR(4) );
INSERT INTO #ExamData ( Student_id, Class_id, Office_Id, Exam_Id, [Status] )
VALUES
( 1, 1, 1, 1, 'Pass' ),
( 2, 1, 1, 1, 'Pass' ),
( 9, 1, 1, 1, 'Fail' ),
( 10, 1, 1, 1, 'Fail' ),
( 1, 1, 1, 2, 'Pass' ),
( 2, 1, 1, 2, 'Fail' );
-- What exam has been passed?
DECLARE #PassedExamNo INT = 1;
-- Show students who have passed the specified exam and are eligible for the next.
-- Excludes:
-- Students who failed required exam.
-- Students who have already passed the next sequential exam.
-- Assumption: Exam ids are incremented by 1 for each sequential exam.
SELECT * FROM #ExamData AS e
WHERE
Office_Id = 1
AND Class_Id =1
AND Exam_Id = #PassedExamNo
AND [Status] = 'Pass'
AND NOT EXISTS (
SELECT * FROM #ExamData AS x WHERE
x.Office_Id = e.Office_Id AND x.Student_id = e.Student_id AND x.Exam_Id = ( e.Exam_Id + 1 ) AND x.[Status] = 'Pass'
);
Returns any student(s) who are eligible for the next exam:
+------------+----------+-----------+---------+--------+
| Student_id | Class_id | Office_Id | Exam_Id | Status |
+------------+----------+-----------+---------+--------+
| 2 | 1 | 1 | 1 | Pass |
+------------+----------+-----------+---------+--------+
You can run the above example in SSMS.
You can try the below query once. This will give the each student and the last exam he has taken and status
SELECT student_Id
,Exam_Id
,[Status]
FROM (
SELECT student_Id
,Exam_Id
,[Status]
,ROW_NUMBER() OVER (
PARTITION BY student_Id ORDER BY Exam_Id DESC
) [rownum]
FROM Tbl_StudentsExamMarking
WHERE Office_Id = 1
AND Class_Id = 1
) a
WHERE a.[rownum] = 1
Adding the new query as per your comment.
DECLARE #exam_id INT = 2
SELECT
student_Id
,Exam_Id
,[Status]
FROM Tbl_StudentsExamMarking
WHERE Office_Id = 1
AND Class_Id = 1
AND ((Exam_id = #exam_id AND [Status] = 'Fail')
OR (Exam_id = #exam_id - 1 AND [Status] = 'Pass'))
Sample output for Query 1
This is the complete answer to my query. I resolved after 5 days.
Select st.Student_Id, st.Student_Name,sm.Status,sm.Exam_Id from Tbl_StudentsExamMarking sm
inner join Tbl_Students st on st.Student_Id = sm.Student_Id
where sm.Office_Id = 1 and sm.Class_Id = 1 and sm.exam_id=2 and status='Fail' and Month(sm.Exam_Date)=08 and not exists(select * from Tbl_StudentsExamMarking as f where f.Student_Id=sm.Student_Id and f.Office_Id = sm.Office_Id and f.Status = 'pass' and f.Exam_Id = (sm.Exam_Id+1))
and exists(select * from Tbl_StudentsExamMarking as f where f.Student_Id=sm.Student_Id and f.Office_Id = sm.Office_Id and f.Status = 'Pass' and f.Exam_Id = (sm.Exam_Id-1))
and not exists(select * from Tbl_StudentsExamMarking as f where f.Student_Id=sm.Student_Id and f.Office_Id = sm.Office_Id and f.Status = 'Pass' and f.Exam_Id = (sm.Exam_Id))
--AND NOT EXISTS (SELECT * FROM Tbl_StudentsExamMarking AS x WHERE x.Office_Id = sm.Office_Id AND x.Student_id = sm.Student_id AND x.Exam_Id = ( sm.Exam_Id ) AND x.[Status] = 'Fail')
Union
Select st.Student_Id, st.Student_Name,sm.Status,sm.Exam_Id from Tbl_StudentsExamMarking sm
inner join Tbl_Students st on st.Student_Id = sm.Student_Id
where sm.Office_Id = 1 and sm.Class_Id = 1 and sm.exam_id=1 and status='Pass' and Month(sm.Exam_Date)=08
AND NOT EXISTS (SELECT * FROM Tbl_StudentsExamMarking AS x WHERE x.Office_Id = sm.Office_Id AND x.Student_id = sm.Student_id AND x.Exam_Id = ( sm.Exam_Id + 1 ) AND x.[Status] = 'Pass')
AND NOT EXISTS (SELECT * FROM Tbl_StudentsExamMarking AS x WHERE x.Office_Id = sm.Office_Id AND x.Student_id = sm.Student_id AND x.Exam_Id = ( sm.Exam_Id + 1 ) AND x.[Status] = 'Fail')

TSQL Pivoting multiple columns

Code:
DECLARE #Employee TABLE
(
[Employee_Id] INT IDENTITY(1, 1)
, [Code] NVARCHAR(10)
) ;
INSERT INTO #Employee
VALUES ( N'E1' ), ( N'E2' ), ( N'E3' ) ;
DECLARE #Contact TABLE
(
[Employee_Id] INT
, [PhoneType] CHAR(1)
, [PhoneNumber] VARCHAR(20)
, [IsMainNumber] BIT
) ;
INSERT INTO #Contact
VALUES (1, 'M', '1234567890', 1), (1, 'H', '1234567891', 0),
(1, 'M', '1234567892', 0), (1, 'B', '1234567893', 0),
(2, 'M', '2234567890', 0), (2, 'H', '2234567891', 1),
(2, 'B', '2234567892', 0), (2, 'M', '2234567893', 0),
(3, 'M', '3234567890', 0), (3, 'H', '3234567891', 0),
(3, 'M', '3234567892', 0), (3, 'B', '3234567893', 1);
SELECT
[E].[Employee_Id],
[E].[Code],
[COA].[MainPhoneNumber],
[COA].[NonMainNumber]
FROM
#Employee AS [E]
OUTER APPLY
(SELECT
MAX (IIF([C].[IsMainNumber] = 1, [C].[PhoneNumber], NULL)) [MainPhoneNumber],
MAX (IIF([C].[IsMainNumber] = 0, [C].[PhoneNumber], NULL)) [NonMainNumber]
FROM
#Contact AS [C]
WHERE
[E].[Employee_Id] = [C].[Employee_Id]
GROUP BY
[C].[Employee_Id]) AS [COA] ;
Current output
Employee_Id Code MainPhoneNumber NonMainNumber
1 E1 1234567890 1234567893
2 E2 2234567891 2234567893
3 E3 3234567893 3234567892
Goal
I need to return the MAX main phone number and its phone type and MAX non-main phone number and its phone type. I'm able to get the MAX main/non-main phone numbers, but need to somehow get their phone types. I don't want to make two additional joins based on Employee_Id and PhoneNumber and get the type, because original table is huge and that would slow things down a lot. Trying to figure out an alternative that performs well.
Desired Output
Employee_Id Code MainPhoneType MainPhoneNumber NonMainPhoneType NonMainNumber
1 E1 M 1234567890 B 1234567893
2 E2 H 2234567891 M 2234567893
3 E3 B 3234567893 M 3234567892
Seems you need two apply :
select e.Employee_Id, e.Code,
c.PhoneType as MainPhoneType, c.PhoneNumber as MainPhoneNumber,
c1.PhoneType as NonMainPhoneType, c1.PhoneNumber as NonMainNumber
from #Employee e outer apply
(select top (1) c.PhoneType, c.PhoneNumber
from #Contact c
where c.Employee_Id = e.Employee_Id and
c.IsMainNumber = 1
order by c.phonetype
) c outer apply
(select top (1) c1.PhoneType, c1.PhoneNumber
from #Contact c1
where c1.Employee_Id = e.Employee_Id and
c1.IsMainNumber = 0
order by c1.phonetype
) c1;
If you don't want to do JOIN two times then you can use temp table just dump the contacts with relevant index
#temp (Employee_Id, IsMainNumber) include (PhoneType, PhoneNumber)
insert into #temp (Employee_Id, PhoneType, PhoneNumber, IsMainNumber)
select Employee_Id, PhoneType, PhoneNumber, IsMainNumber
from (select *, row_number() over (partition by Employee_Id, IsMainNumber order by PhoneType) as seq
from #Contact
) c
where seq = 1
Now, you don't need to use #Contact again :
select e.*, m.*
from #Employee e cross apply
(select max(case when t.IsMainNumber = 1 then t.PhoneType end) as MainPhoneType,
max(case when t.IsMainNumber = 1 then t.PhoneNumber end) as MainPhoneNumber,
max(case when t.IsMainNumber = 0 then t.PhoneType end) as NonMainPhoneType,
max(case when t.IsMainNumber = 0 then t.PhoneNumber end) as NonMainNumber
from #temp t
where t.Employee_Id = e.Employee_Id
) m;
Not really sure how you determine which nonMainNumber is the one you want. Seems that most of your sample data has several rows that could be returned. I will leave that exercise to you. Here is how you could use some conditional aggregation for this.
select x.Employee_Id
, x.Code
, MainPhoneType = max(case when x.RowNum = 1 then x.PhoneType end)
, MainPhoneNumber = max(case when x.RowNum = 1 then x.PhoneNumber end)
, NonMainPhoneType = max(case when x.RowNum = 2 then x.PhoneType end)
, NonMainPhoneNumber = max(case when x.RowNum = 2 then x.PhoneNumber end)
from
(
select e.Employee_Id
, e.Code
, c.PhoneType
, c.PhoneNumber
, RowNum = ROW_NUMBER() over(partition by e.Employee_Id order by c.IsMainNumber desc, c.PhoneType) --Not sure how you determine the non MainNumber when there are several to pick from
from #Employee e
join #Contact c on c.Employee_Id = e.Employee_Id
) x
group by x.Employee_Id
, x.Code
You can do this with conditional aggregation:
select e.Employee_Id, e.Code
max(case when seqnum = 1 and c.PhoneType = 'M' then c.PhoneType end) as MainPhoneType
max(case when seqnum = 1 and c.PhoneType = 'M' then x.PhoneNumber end) as MainPhoneNumber,
max(case when seqnum = 1 and c.PhoneType <> 'M' then c.PhoneType end) as NonMainPhoneType
max(case when seqnum = 1 and c.PhoneType <> 'M' then c.PhoneNumber end) as NonMainPhoneNumber
from #Employee e join
(select c.*,
row_number() over (partition by c.Employee_Id
(case when PhoneType = 'M' then 'M' end)
order by c.PhoneNumber desc
) as seqnum
from #Contact c
) c
on c.Employee_Id = e.Employee_Id
group by e.Employee_Id, e.Code;
The key idea in this logic is the partition by clause. It divides the two types of phones into two groups -- with 'M' for "main" and NULL for all else.

Filter maximum value from sql count query

I currently have the following query
SELECT organisation.organisationID, COUNT(organisation.organisationID)
FROM position, positionLocation, organisation
WHERE position.positionLocationID = positionLocation.positionLocationID AND
positionLocation.organisationID = organisation.organisationID AND
position.status = 'Open'
GROUP BY organisation.organisationID;
This query outputs
organisationID | countOrganisationID
1 3
3 2
5 3
I would like to display records that have max countOrganisationID. Ideally i would just like output the organisationID with its corresponding organisationName if possible.
Something along the lines of
organisationID | organisatioName
1 name1
5 name2
Any help would be appreciate
Thanks
Barrett is right, RANK() is the way to go, e.g.:
SELECT organisationID, c FROM (
SELECT organisationID
,c
,RANK() OVER (ORDER BY c DESC) r
FROM (
SELECT organisation.organisationID
,COUNT(organisation.organisationID) AS c
FROM position, positionLocation, organisation
WHERE position.positionLocationID = positionLocation.positionLocationID
AND positionLocation.organisationID = organisation.organisationID
AND position.status = 'Open'
GROUP BY organisation.organisationID
)
) WHERE r = 1;
Could just subquery it:
WITH counts AS (
SELECT organisation.organisationID
,organisation.organisationName
,COUNT(organisation.organisationID) the_count
FROM position, positionLocation, organisation
WHERE position.positionLocationID = positionLocation.positionLocationID
AND positionLocation.organisationID = organisation.organisationID
AND position.status = 'Open'
GROUP BY organisation.organisationID, organisation.organisationName
)
SELECT organisationID, organisationName
FROM counts
WHERE the_count = (SELECT MAX(the_count) FROM counts)
This should work.
SELECT organisationID, organisatioName
FROM position, positionLocation, organisation
WHERE position.positionLocationID = positionLocation.positionLocationID AND
positionLocation.organisationID = organisation.organisationID AND
position.status = 'Open'
AND COUNT(organisation.organisationID) =
SELECT MAX(cnt) AS MaxCnt FROM
SELECT organisation.organisationID, COUNT(organisation.organisationID) AS cnt
FROM organisation
WHERE position.status = 'Open'
GROUP BY organisation.organisationID
GROUP BY organisation.organisationID, organisation.organisatioName;