Outer Join Returns Multiple Rows - sql

I am joining APPS.PER_JOBS on PER_ALL_ASSIGNMENTS_F, looking to get current row - but I get multiple rows unless I add REQUEST_ID to the join. However, when I do this - though it supresses the mulitple rows - it also causes the substring I use to pull Title to return a Null value for all records. How can I join these tables to pull only the current row without causing my Title substring to null out?
Here's the outer join I have right now:
APPS.PER_ALL_ASSIGNMENTS_F B
LEFT OUTER JOIN (SELECT *
FROM APPS.PER_JOBS F_ED
WHERE F_ED.DATE_FROM = (SELECT MAX(F_ED1.DATE_FROM)
FROM APPS.PER_JOBS F_ED1
WHERE F_ED1.JOB_ID = F_ED.JOB_ID
AND F_ED1.DATE_FROM <= SYSDATE)) F
ON F.JOB_ID = B.JOB_ID
AND F.REQUEST_ID = B.REQUEST_ID
And here's the title substring:
SUBSTR(F.NAME,INSTR(F.NAME,'.')+1) AS "Occupation"
Thanks,
Steve
Edit: Here's an example:
Without ‘F.REQUEST_ID = B.REQUEST_ID’:
Employee Number Occupation
597 Manager, Special Events
632 Web Developer
632 Software Developer
8392 Development Intern
8392 Software Developer
With ‘F.REQUEST_ID = B.REQUEST_ID’:
Employee Number Occupation
597
632
8392

Related

T-SQL subselect statement is returning all rows instead of limiting to 1 based on subselect

I am trying to return just the first row where the BLOCK_STOP_ORDER = 2. What is wrong with my SQL? Why isn't WHERE SCHEDULE.BLOCK_STOP_ORDER = (SELECT MIN(S1.BLOCK_STOP_ORDER....
working? When I run the subselect on its own it returns the value '2' - doesn't that mean it should then limit the query result to only the row(s) where BLOCK_STOP_ORDER = 2?
SELECT ROUTE.ROUTE_ABBR, SCHEDULE.ROUTE_DIRECTION_ID, SCHEDULE.PATTERN_ID, SCHEDULE.BLOCK_STOP_ORDER,
SCHEDULE.SCHEDULED_TIME, GEO_NODE.GEO_NODE_ABBR, TRIP.TRIP_SEQUENCE AS TPST
FROM SCHEDULE
INNER JOIN GEO_NODE ON SCHEDULE.GEO_NODE_ID = GEO_NODE.GEO_NODE_ID
INNER JOIN ROUTE ON SCHEDULE.ROUTE_ID = ROUTE.ROUTE_ID
INNER JOIN TRIP ON SCHEDULE.TRIP_ID = TRIP.TRIP_ID
WHERE (SCHEDULE.CALENDAR_ID = '120221024') AND ROUTE.ROUTE_ABBR = '001'
AND SCHEDULE.ROUTE_DIRECTION_ID = '2' AND SCHEDULE.PATTERN_ID = '270082'
AND TRIP.TRIP_SEQUENCE = '18600'
AND SCHEDULE.BLOCK_STOP_ORDER =
(SELECT MIN(S1.BLOCK_STOP_ORDER)
FROM SCHEDULE S1
WHERE SCHEDULE.CALENDAR_ID = S1.CALENDAR_ID
AND SCHEDULE.ROUTE_ID = S1.ROUTE_ID
AND SCHEDULE.ROUTE_DIRECTION_ID = S1.ROUTE_DIRECTION_ID
AND SCHEDULE.PATTERN_ID = S1.PATTERN_ID
AND SCHEDULE.SCHEDULED_TIME = S1.SCHEDULED_TIME
AND SCHEDULE.GEO_NODE_ID = S1.GEO_NODE_ID
AND SCHEDULE.BLOCK_STOP_ORDER = S1.BLOCK_STOP_ORDER
AND SCHEDULE.TRIP_ID = S1.TRIP_ID
)
GROUP BY ROUTE.ROUTE_ABBR, SCHEDULE.ROUTE_DIRECTION_ID,
SCHEDULE.PATTERN_ID, SCHEDULE.SCHEDULED_TIME,
GEO_NODE.GEO_NODE_ABBR, SCHEDULE.BLOCK_STOP_ORDER, TRIP.TRIP_SEQUENCE
ORDER BY ROUTE.ROUTE_ABBR, SCHEDULE.ROUTE_DIRECTION_ID, TRIP.TRIP_SEQUENCE
Results:
ROUTE_ABBR
ROUTE_DIRECTION_ID
PATTERN_ID
BLOCK_STOP_ORDER
SCHEDULED_TIME
GEO_NODE_ABBR
TPST
001
2
270082
2
18600
1251
18600
001
2
270082
3
18600
1346
18600
001
2
270082
5
18720
1123
18600
001
2
270082
6
18720
11372
18600
001
2
270082
4
18720
1570
18600
001
2
270082
8
18780
11373
18600
This is probably better solved with the row_number() windowing function:
SELECT *
FROM (
SELECT DISTINCT r.ROUTE_ABBR, s.ROUTE_DIRECTION_ID, s.PATTERN_ID, s.BLOCK_STOP_ORDER,
s.SCHEDULED_TIME, g.GEO_NODE_ABBR, t.TRIP_SEQUENCE AS TPST,
row_number() over (order by SCHEDULE.BLOCK_STOP_ORDER) rn
FROM SCHEDULE s
INNER JOIN GEO_NODE g ON s.GEO_NODE_ID = g.GEO_NODE_ID
INNER JOIN ROUTE r ON s.ROUTE_ID = r.ROUTE_ID
INNER JOIN TRIP t ON s.TRIP_ID = t.TRIP_ID
WHERE s.CALENDAR_ID = '120221024' AND r.ROUTE_ABBR = '001'
AND s.ROUTE_DIRECTION_ID = '2' AND s.PATTERN_ID = '270082'
AND t.TRIP_SEQUENCE = '18600'
) t1
WHERE rn=1
ORDER BY t1.ROUTE_ABBR, t1.ROUTE_DIRECTION_ID, t1.TRIP_SEQUENCE
The problem with the original is the name SCHEDULE. For the full version of the query, the subquery is matching the name in the nested select with the instance of the table from the outer select. This correlates the results of the inner table with the outer, so only the item from that row of the outer table is eligible.
When you run the inner query by itself, separate from the outer query, there is only the one instance of the table. In that situation the WHERE conditions are matching the table to itself — they are always true — and you just get the smallest value of all the rows: 2.
This is why you should ALWAYS give ALL the tables in your queries an alias, and ONLY reference them by that alias (as I did in my answer). Do this, and the MIN() version can work... but will still be slower and more code than using row_number().
Finally, the use of DISTINCT / GROUP BY with every SELECT column is usually an indicator you don't fully understand the JOIN relationships used in the query, and in at least one case the join conditions are not sufficiently selective. I'd hesitate to move a query like that to production, even if it seems to be working, though I confess most of us have done it at some point anyway.

SQL Count with join are returning double results

I have two tables, "event" and "soundType". I am trying to count the number of event with specific soundType.
This is my request :
SELECT Count(*) AS nb
FROM event
INNER JOIN soundtype
ON event.id = soundtype.eventid
WHERE ( soundtype.NAME = 'pop'
OR soundtype.NAME = 'rock' )
AND ( event.partytype = 'wedding'
OR event.partytype = 'Corporate evening'
OR event.partytype = 'birthday' )
Example of tables below:
event Table
id userId partyType
----------------------------
249 30 birthday
250 30 wedding
SoundType Table
id evenId name
-----------------------
1 249 pop
2 249 rock
3 250 pop
The result
nb
---
3
The result i expect
nb
---
2
Thank you for your help
You might find that exists is more efficient than count(distinct):
SELECT COUNT(*) AS nb
FROM event e
WHERE e.partytype IN ('wedding', 'Corporate evening' , 'birthday') AND
EXISTS (SELECT 1
FROM soundtype st
WHERE st.eventid = e.id AND
st.NAME IN ('pop', 'rock')
) ;
Your problem is (presumably) arising because some events have multiple sound types. You just need to match one of them. Multiplying out all the rows just to use COUNT(DISTINCT) is inefficient, when EXISTS (or IN) prevents the duplicates in the first place.
You count all the resulting records. But you need to count different events. So use distinct
SELECT COUNT(distinct event.id) AS nb
FROM event
INNER JOIN soundType ON event.id = soundType.eventId
WHERE soundType.name in('pop', 'rock')
AND event.partyType in('wedding', 'Corporate evening', 'birthday')

how to show zero when IN does not return any value sql

I want to return 0 when no rows found for this following condition.
SELECT P.externalid,
Count(DISTINCT Pp.patientuid) patcount
FROM PatientProcedure Pp (nolock )
INNER JOIN visit Temp (nolock )
ON Temp.patientuid = Pp.patientuid
AND (Pp.effectivedate = Temp.VisitDate)
AND Temp.RenderringProviderUid = Pp.serviceprovideruid
AND Temp.VisitDate >= '07-01-2013'
AND Temp.VisitDate <= '06-30-2014'
INNER JOIN serviceprovider Sp (nolock )
ON Pp.serviceprovideruid = Sp.serviceprovideruid
AND Sp.inactive = 0
INNER JOIN MasterCode Mc (nolock )
ON Mc.codeuid = Pp.procedurecodeuid
INNER JOIN MasterCodeSet Mcs (nolock )
ON Mcs.Value = Mc.code
INNER JOIN practice P
ON P.PracticeUid = Temp.practiceuid
WHERE NAME = 'Visual_Field_Exam'
AND Temp.mastervisittypeuid IS NOT NULL
AND P.ExternalID IN ('26900', '26902', '26903', '26906',
'26907', '26908', '26946', '26963',
'27128', '27131', '27133', '27134',
'27135', '27137', '27166', '27167',
'27497', '27498', '27499', '27501',
'27502', '27504', '27505', '27509',
'27510', '27511', '27518')
GROUP BY P.ExternalID
I have found patient count for many practices but no patient found for one practice. So, I want to return count(patientuid) = 0 for that practice.
Here is the sample data.
PracticeId Patcount
26900 2583
26902 826
26903 4085
26906 241
26907 3205
26908 4592
26946 344
26963 398
27128 238
27131 2467
27133 975
27135 815
27137 1252
27166 1038
27167 211
27497 1053
27498 934
27499 3467
27501 617
27502 3511
27504 7222
27505 683
27509 210
27510 1145
27511 181
27518 500
In above output I got data for 26 practices, but "27134" practice does not having patient count, so i want it show 0.
I want above output. How can I achieve it?
Thanks in advance..!
Suppose you have a table Practicer which holds the practicers (i do not know if that is the correct word, but doesn't matter for SQL). Then you need to left join that table with Patient in order to get a list of all Practicers filter by you where clause. So this will get the ones you want.
Select PR.PracticeName,
count(distinct patientid)
from Practicer PR
LEFT JOIN Patient P
ON PR.Practiceid = P.Practiceid
where PR.Practiceid in
('12345','65478','78541')
GROUP BY PR.PracticeName
In general, you want to return 2 fields. The first is the list of Hospitals, Practiotioners or whatever else you may like. In order to get the full list (even if it does not have a count) you need to start with that table.
Lets say we have a table Hospitals that we want to filter on specific ids. The we would have the following query:
SELECT HospitalId,
HospitalName
FROM Hospitals
WHERE HospitalId IN ('26900', '26902', '26903')
Now we would like to know the no of patients in each hospital. We know that hospital with id '26902' has no patients (WOW). If we would go to the Patients table and tried the following:
SELECT HospitalId,
COUNT(*) AS NoOfPatients
FROM Patients
WHERE HospitalId IN ('26900', '26902', '26903')
GROUP BY HospitalId
It would return only ids '26900' and '26903' as the Hospital with id '26902' does not have any patient.
So, how do we figure out the third Hospital?
We join the two tables:
SELECT H.HospitalId,
COUNT(PatienId) AS NoOfPatients
FROM Hospitals H
LEFT JOIN Patients P
WHERE H.HospitalId IN ('26900', '26902', '26903')
GROUP BY H.HospitalId
Now this would return all the requested hospitals with the according number of patients.
Your case is more complex, as we need more joins from the Hospitals to the Patients tables. But i hope my explanation will get you on the right track.
The essence of it is to start from your List Table to your Count table.

Merge multiple rows in data to show only a single row in the result

I have a stored procedure which takes 1 parameter, an ID number (systudentid).
The procedure returns 3 rows: a student’s academic counselor (AC), financial counselor (FC), and admissions counselor (EC) along with relevant contact information; 3 different people.
Certain students have ACs and FCs who are the same person, but the query will still return 3 rows.
AdvisorType|AdvisorLastName|AdvisorFirstName|(other data)|systaffID
AC DOE JOHN ..... 12345
AC DOE JOHN ..... 12345
EC SMITH JANE ..... 45678
Where in my code can I plug in the logic (and how, I'm a newbie with sql) so that when the systudentid passed to the procedure identifies a student having the same person for both AC and FC, it will display the results this way.
The advisor type is changed to "SSA" and only one of the records for the double-duty counselor is returned.
AdvisorType|AdvisorLastName|AdvisorFirstName|(other data)|SystaffID
SSA DOE JOHN ...... 12345
EC SMITH JANE ...... 45678
Here is my select statement:
SELECT
SyStaffGroup.Descrip AS AdvisorType
,SyStaff.LastName AS AdvisorLastName
,SyStaff.FirstName AS AdvisorFirstName
,SyStaff.Phone AS AdvisorPhone
,SyStaff.Ext AS AdvisorExtention
,SyStaff.eMail AS AdvisorEMail
,SyStaff.SyStaffID AS SyStaffID
FROM SyStaff (NOLOCK)
JOIN SyAdvisorByEnroll (NOLOCK)
ON SyAdvisorByEnroll.SyStaffID = SyStaff.SyStaffID
JOIN SyStaffGroup (NOLOCK)
ON SyStaffGroup.SyStaffGroupID = SyAdvisorByEnroll.SyStaffGroupID
JOIN AdEnroll (NOLOCK)
ON AdEnroll.AdEnrollID = SyAdvisorByEnroll.AdEnrollID
JOIN SyStudent (NOLOCK)
ON AdEnroll.SyStudentID = SyStudent.SyStudentId
WHERE
SyStaff.Active = 1
--AND
--syadvisorbyenroll.adenrollid = (
--SELECT adenrollid from dbo.fn_student_enrollment_activeenrollmentlist (#systudentid)
--)
AND adEnroll.adEnrollID IN (
SELECT adEnrollID FROM dbo.fn_Student_Enrollment_ActiveEnrollmentList(#SyStudentID)
)
AND SyAdvisorByEnroll.AdvisorModule IN ('AD','FA')
AND SyStaffGroup.Descrip IN ('AC - Academic Counselor', 'FC - Finance Counselors', 'EC - Adm. Counselor With Reg')
UNION
SELECT DISTINCT
'Admissions Counselor' AS AdvisorType
,SyStaff.LastName AS AdvisorLastName
,SyStaff.FirstName AS AdvisorFirstName
,SyStaff.Phone AS AdvisorPhone
,SyStaff.Ext AS AdvisorExtention
,SyStaff.eMail AS AdvisorEMail
,SyStaff.SyStaffID AS SyStaffID
FROM systudent
INNER JOIN AmRep ON SyStudent.AMREpID = AmREp.AMREpid
INNER JOIN SyStaff ON SyStaff.SyStaffID = AmRep.AmRepID
WHERE Systudent.SYStudentid = #systudentid
Any hints or suggested methods that I can either try or Google (I've tried searching but results are a lot more useful if I knew what to look for) would be greatly appreciated.
You can add a nested subquery to indicate which students have the same advisor filling multiple positions, and adjust the type selection accordingly. Here are the changed portions of your above query:
SELECT
CASE WHEN (mutiples.SyStaffID IS NOT NULL) THEN 'SSA'
ELSE SyStaffGroup.Descrip END AS AdvisorType
-- other columns omitted
FROM SyStaff (NOLOCK)
JOIN SyAdvisorByEnroll (NOLOCK)
ON SyAdvisorByEnroll.SyStaffID = SyStaff.SyStaffID
LEFT JOIN (
SELECT SyStaffID,AdEnrollID
FROM SyAdvisorByEnroll
GROUP BY SyStaffID,AdEnrollID
HAVING COUNT(DISTINCT SyStaffGroupID) > 1
) multiples
ON multiples.SyStaffID = SyAdvisorByEnroll.SyStaffID
AND multiples.AdEnrollID = SyAdvisorByEnroll.AdEnrollID
-- rest of query omitted
This might have a mistake or two, since you didn't include your table schema. The nested subquery, "multiples", contains all advisor / enrollee pairs where the advisor is in multiple groups. You left join against this and adjust the final type selection to "SSA" if there's a matching entry in the nested subquery.
An important note: as written, this will include two SSA rows for an eligible advisor / enrollee pair. However, the final results will not, because you are using a UNION in this query, which filters out duplicates, even if they're only present in one half of the union. If you change this to UNION ALL or eliminate the UNION entirely, you will need to add DISTINCT to the top of the query, like so:
SELECT DISTINCT CASE WHEN (mutiples.SyStaffID IS NOT NULL) ...

SQL Server Query for Many to Many Relationship

I have the following Many to many relationship (See the picture below) in my SQL server.
In most cases there's are 2 rows in table tblWavelengths related to the table tblSensors, (in some cases only 1, and in extreme cases there can be 20 rows)
I made the following simple query to retrieve the data from those 3 tables :
select W.DateTimeID,S.SensorName,S.SensorType,W.Channel,W.PeakNr,W.Wavelength
from tblWavelengths as W
Left Join tblSensorWavelengths as SW on W.tblWavelengthID = SW.WavelengthID
Left Join tblSensors as S on SW.SensorID = S.SensorID
order by W.DateTimeID
After running this query I got the following results :
Here comes my problem. I want to write a query which filters only those Sensors (SensorName) which at a given moment in time (DateTimeID) has two rows (two different wavelengths) in the tblWavelengths table. So for example I want to have the results without
the 77902/001 Sensor - because it has only one row (one Wavelength) related to the tblSensors at a given moment in time
You could use a windowed function to find out the number of wavelengths for each sensorname/datetimeid combination:
WITH Data AS
( SELECT W.DateTimeID,
S.SensorName,
S.SensorType,
W.Channel,
W.PeakNr,
W.Wavelength,
[Wcount] = COUNT(*) OVER(PARTITION BY s.SensorName, d.DateTimeID)
from tblWavelengths as W
LEFT JOIN tblSensorWavelengths as SW
ON W.tblWavelengthID = SW.WavelengthID
LEFT JOIN tblSensors as S
ON SW.SensorID = S.SensorID
)
SELECT DateTimeID, SensorName, SensorType, Channel, PeakNr, WaveLength
FROM Data
WHERE Wcount = 2
ORDER BY DateTimeID;
ADDENDUM
As an after thought I realised that you might have two results for one sensor at the same time with the same wavelength, which would return 2 records, but not have two different wavelengths. Since windowed functions don't support the use of DISTINCT an alternative is below
WITH Data AS
( SELECT W.DateTimeID,
S.SensorName,
S.SensorType,
W.Channel,
W.PeakNr,
W.Wavelength,
W.tblWaveLengthID
from tblWavelengths as W
LEFT JOIN tblSensorWavelengths as SW
ON W.tblWavelengthID = SW.WavelengthID
LEFT JOIN tblSensors as S
ON SW.SensorID = S.SensorID
)
SELECT d.DateTimeID, d.SensorName, d.SensorType, d.Channel, d.PeakNr, d.WaveLength
FROM Data d
INNER JOIN
( SELECT DateTimeID, SensorName
FROM Data
GROUP BY DateTimeID, SensorName
HAVING COUNT(DISTINCT tblWaveLengthID) = 2
) t
ON t.DateTimeID = d.DateTimeID
AND t.SensorName = d.SensorName
ORDER BY d.DateTimeID;