PIVOT on multiple columns SQL server (Aspen Relay Database) - sql

I'm using a vendor supplied Relay Database (Aspen), which is running on MS SQL server). I'm attempting to write a pivot query that needs to pivot on 2 columns.
I created a temp table since the data is across multiple tables.
WITH TEMP_TABLE AS (
SELECT
R.LOCATIONID LLOCATIONID, R.ID RID, s.groupname SGROUPNAME,t.settingname TSETTINGNAME, s.setting SSETTING
from tsetting1 s
inner join tsettype1 t on t.relaytype=s.relaytype and t.groupname = s.groupname and t.rownumber = s.rownumber
INNER JOIN TREQUEST Q ON S.REQUESTID = Q.ID
INNER JOIN TRELAY R ON R.ID = Q.RELAYID
INNER JOIN TLOCATION L ON L.ID = R.LOCATIONID
where s.requestid=29117
)
select * from TEMP_TABLE
That select all from Temp returns 38 rows of data, a subset is shown here:
RID -----SGROUPNAME------TSETTINGNAME-------SSETTING
31297 LOAD1 ENABLE TRUE
31297 LOAD1 ANGLE 60
31297 LOAD2 CALCULATED_LOAD 12269
ETC....
I added this pivot, which gets me close:
PIVOT (MAX(SSETTING) FOR TSETTINGNAME IN (ENABLE, REACH, ANGLE, CALCULATED_LOADABILITY, ZLE, CTR, PTR, KVNOM, PICKUP, PERCENTAGE)) P
Returned result from Pivot:
RID-----SGROUPNAME-----ENABLE----REACH----ANGLE----CALCULATED_LOADABILITY
31297 LOAD1 TRUE 15 60 9444
31297 LOAD2 TRUE 10 30 12269
31297 LOAD3 TRUE 20 60 14167
ETC...
I would like to have the data as 1 record for RID 31297, where LOAD1-ENABLE, LOAD2-ENABLE, LOAD3-ENABLE, LOAD1-REACH, ETC. are all headers.
I've tried multiple pivots and cross apply, but I can't seem to get the data to display correctly.
Let me know if anything is unclear or if you need more information. Any help will be greatly appreciated.
Thanks,
Joe C.

It may be easier with a bunch of case statements and a group by RID. By the way this is the "original" method of pivoting before PIVOT was implemented.
select RID
, Load1_Enable = MAX(case when SGROUPNAME = 'Load1' then enable else null end)
, Load2_Enable = MAX(case when SGROUPNAME = 'Load2' then enable else null end)
from [YourTable]
group by RID
I would go all the way to the first cte though:
WITH TEMP_TABLE AS (
SELECT
R.LOCATIONID LLOCATIONID, R.ID RID, s.groupname SGROUPNAME,t.settingname TSETTINGNAME, s.setting SSETTING
from tsetting1 s
inner join tsettype1 t on t.relaytype=s.relaytype and t.groupname = s.groupname and t.rownumber = s.rownumber
INNER JOIN TREQUEST Q ON S.REQUESTID = Q.ID
INNER JOIN TRELAY R ON R.ID = Q.RELAYID
INNER JOIN TLOCATION L ON L.ID = R.LOCATIONID
where s.requestid=29117
)
select RID
,Load1_Enable = MAX(case when SGROUPNAME = 'Load1' and TSETTINGNAME = 'Enable' then SSETTING else null end)
from TEMP_TABLE
group by RID
Note MAX is only there for an aggregate -- you should be aggregating only one record.

Related

SQL Server : Pivot Table Odd result,

So, full disclosure, this is my first time using a pivot table and the result set has multiple columns as a result. In this example, we will use the result set without a pivot table applied.
This student has taken multiple courses. What the ideal end result would be, is to count how many courses this student has taken. So if I look I see that the Student has taken Algebra 1 5 times, English 1 2 times and Geometry 2 times.
The Next image is the query with the pivot applied, oh and to make things complicated, its a monster query before trying to attempt the pivot.
So we see in this, that Algebra 1 has a count of 0, Geometry has a count of 2 and English has a count of 0. This is the same query as before but just using this student.
Query:
SELECT *
FROM
(SELECT
[StudentNumber], psat.MathScaledScore, psat.EBRWScore,
SCReady.MathScaleScore, SCReady.ReadingScaleScore,
SpringMap.MathPercentile, SpringMap.ReadingPercentile,
Coursework.Course_name
FROM
[OnlineApplications].[dbo].[Users] U
LEFT JOIN
[OnlineApplications].[dbo].ContactInfoes C ON C.ContactInfoId = U.UserId
LEFT JOIN
(SELECT *
FROM [DOENRICH-SQL].[enrich_prod].dbo.HCS_view_Most_Recent_PSAT_Scores Scores) AS psat ON U.StudentNumber = psat.number
LEFT JOIN
(SELECT
stud.Number, sc.DateTaken,
CASE sc.ELALev
WHEN 'E8AE0E4D-AD36-41D8-AC89-627D19661803' THEN 'Exceeds Expectations'
WHEN 'C9F2CDA2-D904-438B-9DD3-94EFC9111A0E' THEN 'Approaches Expectations'
WHEN '9B39E28F-89C8-44AD-A8F2-1463192F88F1' THEN 'Does Not Meet Expectation'
WHEN '87247DB1-4A57-419E-9619-7B43B02B1135' THEN 'Meets Expectations'
END ELALev,
sc.ELASS AS ELAScaleScore, sc.elavss AS VerticalScaleScore,
sc.elassread AS ReadingScaleScore,
sc.ELARS10 AS RawScoreStandard10, sc.elASPR AS ELAStatePercentileRank,
MathLev = CASE MathLev
WHEN 'E8AE0E4D-AD36-41D8-AC89-627D19661803' THEN 'Exceeds Expectations'
WHEN 'C9F2CDA2-D904-438B-9DD3-94EFC9111A0E' THEN 'Approaches Expectations'
WHEN '9B39E28F-89C8-44AD-A8F2-1463192F88F1' THEN 'Does Not Meet Expectation'
WHEN '87247DB1-4A57-419E-9619-7B43B02B1135' THEN 'Meets Expectations'
END,
sc.MATHSS AS MathScaleScore, sc.MathVSS AS MathVerticalScaleScore,
sc.mathspr AS MathStatePercentileRank
FROM
[DOENRICH-SQL].[enrich_prod].dbo.t_sc_ready sc
JOIN
[DOENRICH-SQL].[enrich_prod].dbo.Student stud ON sc.StudentID = stud.ID
WHERE
DateTaken = '2019-05-17') AS SCReady ON SCReady.number = U.studentnumber
LEFT JOIN
(
select stud.Number, max(map.readingPercentile) as ReadingPercentile, max(map.mathPercentile) as MathPercentile
from [DOENRICH-SQL].[ENRICH_PROD].[dbo].t_map map
join [DOENRICH-SQL].[ENRICH_PROD].[INFORM].[Map_GradeLevelID] mapping on map.GradeLevelID = mapping.DestID
JOIN [DOENRICH-SQL].[ENRICH_PROD].[dbo].[Student] stud on map.StudentID = stud.ID
where DateTaken >= '2018-08-01'
group by stud.Number
) as SpringMap on SpringMap.number = U.Studentnumber
left join (
SELECT * FROM OPENQUERY(PSPROD,'
Select B.STUDENT_NUMBER , A.COURSE_NAME, A.GRADE_LEVEL, A.SCHOOLNAME, A.GRADE
from PS.STOREDGRADES A
join PS.STUDENTS B ON A.STUDENTID = B.ID
AND STORECODE in (''Q1'',''Q2'',''Q3'',''Q4'',''F1'')
AND (COURSE_NAME LIKE ''%Algebra 1%'' OR COURSE_NAME LIKE ''%Geometry Honors%'' OR COURSE_NAME LIKE ''%English 1%'')
group by B.STUDENT_NUMBER , A.COURSE_NAME, a.STORECODE, A.GRADE, A.PERCENT, A.GRADE_LEVEL, A.SCHOOLNAME
ORDER BY STUDENT_NUMBER, STORECODE DESC
'
)
) as Coursework on Coursework.STUDENT_NUMBER = U.StudentNumber
join [OnlineApplications].[dbo].ScholarsApps Sapps on Sapps.ScholarsAppId = u.UserId
where AppYear = 2019 and StudentNumber <> '' and StudentNumber = '17476'
) T
PIVOT (
COUNT (COURSE_NAME)
FOR course_name IN (
[Algebra 1],
[Geometry Honors],
[English 1])
)
as Pivot_table
Again, very complicated query before and I'm not clear if I'm using the pivot function correctly.
I'd love to have this pivot with the counts of the courses.

SQL Server / T-SQL : query optimization assistance

I have this QA logic that looks for errors into every AuditID within a RoomID to see if their AuditType were never marked Complete or if they have two complete statuses. Finally, it picks only the maximum AuditDate of the RoomIDs with errors to avoid showing multiple instances of the same RoomID, since there are many audits per room.
The issue is that the AUDIT table is very large and takes a long time to run. I was wondering if there is anyway to reach the same result faster.
Thank you in advance !
IF object_ID('tempdb..#AUDIT') is not null drop table #AUDIT
IF object_ID('tempdb..#ROOMS') is not null drop table #ROOMS
IF object_ID('tempdb..#COMPLETE') is not null drop table #COMPLETE
IF object_ID('tempdb..#FINALE') is not null drop table #FINALE
SELECT distinct
oc.HotelID, o.RoomID
INTO #ROOMS
FROM dbo.[rooms] o
LEFT OUTER JOIN dbo.[hotels] oc on o.HotelID = oc.HotelID
WHERE
o.[status] = '2'
AND o.orderType = '2'
SELECT
t.AuditID, t.RoomID, t.AuditDate, t.AuditType
INTO
#AUDIT
FROM
[dbo].[AUDIT] t
WHERE
t.RoomID IN (SELECT RoomID FROM #ROOMS)
SELECT
t1.RoomID, t3.AuditType, t3.AuditDate, t3.AuditID, t1.CompleteStatus
INTO
#COMPLETE
FROM
(SELECT
RoomID,
SUM(CASE WHEN AuditType = 'Complete' THEN 1 ELSE 0 END) AS CompleteStatus
FROM
#AUDIT
GROUP BY
RoomID) t1
INNER JOIN
#AUDIT t3 ON t1.RoomID = t3.RoomID
WHERE
t1.CompleteStatus = 0
OR t1.CompleteStatus > 1
SELECT
o.HotelID, o.RoomID,
a.AuditID, a.RoomID, a.AuditDate, a.AuditType, a.CompleteStatus,
c.ClientNum
INTO
#FINALE
FROM
#ROOMS O
LEFT OUTER JOIN
#COMPLETE a on o.RoomID = a.RoomID
LEFT OUTER JOIN
[dbo].[clients] c on o.clientNum = c.clientNum
SELECT
t.*,
Complete_Error_Status = CASE WHEN t.CompleteStatus = 0
THEN 'Not Complete'
WHEN t.CompleteStatus > 1
THEN 'Complete More Than Once'
END
FROM
#FINALE t
INNER JOIN
(SELECT
RoomID, MAX(AuditDate) AS MaxDate
FROM
#FINALE
GROUP BY
RoomID) tm ON t.RoomID = tm.RoomID AND t.AuditDate = tm.MaxDate
One section you could improve would be this one. See the inline comments.
SELECT
t1.RoomID, t3.AuditType, t3.AuditDate, t3.AuditID, t1.CompleteStatus
INTO
#COMPLETE
FROM
(SELECT
RoomID,
COUNT(1) AS CompleteStatus
-- Use the above along with the WHERE clause below
-- so that you are aggregating fewer records and
-- avoiding a CASE statement. Remove this next line.
--SUM(CASE WHEN AuditType = 'Complete' THEN 1 ELSE 0 END) AS CompleteStatus
FROM
#AUDIT
WHERE
AuditType = 'Complete'
GROUP BY
RoomID) t1
INNER JOIN
#AUDIT t3 ON t1.RoomID = t3.RoomID
WHERE
t1.CompleteStatus = 0
OR t1.CompleteStatus > 1
Just a thought. Streamline your code and your solution. you are not effectively filtering your datasets smaller so you continue to query the entire tables which is taking a lot of your resources and your temp tables are becoming full copies of those columns without the indexes (PK, FK, ++??) on the original table to take advantage of. This by no means is a perfect solution but it is an idea of how you can consolidate your logic and reduce your overall data set. Give it a try and see if it performs better for you.
Note this will return the last audit record for any room that has either not had an audit completed or completed more than once.
;WITH cte AS (
SELECT
o.RoomId
,o.clientNum
,a.AuditId
,a.AuditDate
,a.AuditType
,NumOfAuditsComplete = SUM(CASE WHEN a.AuditType = 'Complete' THEN 1 ELSE 0 END) OVER (PARTITION BY o.RoomId)
,RowNum = ROW_NUMBER() OVER (PARTITION BY o.RoomId ORDER BY a.AuditDate DESC)
FROm
dbo.Rooms o
LEFT JOIN dbo.Audit a
ON o.RoomId = a.RoomId
WHERE
o.[Status] = 2
AND o.OrderType = 2
)
SELECT
oc.HotelId
,cte.RoomId
,cte.AuditId
,cte.AuditDate
,cte.AuditType
,cte.NumOfAuditsComplete
,cte.clientNum
,Complete_Error_Status = CASE WHEN cte.NumOfAuditsComplete > 1 THEN 'Complete More Than Once' ELSE 'Not Complete' END
FROM
cte
LEFT JOIN dbo.Hotels oc
ON cte.HotelId = oc.HotelId
LEFT JOIN dbo.clients c
ON cte.clientNum = c.clientNum
WHERE
cte.RowNum = 1
AND cte.NumOfAuditsComplete != 1
Also note I changed your
WHERE
o.[status] = '2'
AND o.orderType = '2'
TO
WHERE
o.[status] = 2
AND o.orderType = 2
to be numeric without the single quotes. If the data type is truely varchar add them back but when you query a numeric column as a varchar it will do data conversion and may not take advantage of indexes that you have built on the table.

SQL Query including pivot

I have done a query which include the left outer join and the pivot.
However I keep getting a bugs saying incorrect column.
SELECT * FROM
(select Max(datetimestamp)as datetimestamp, currentSet, tGroup_id from tPhos_Line_Operator
group by currentSet, tGroup_id)T
LEFT OUTER JOIN
(SELECT PO.tGroup_id AS G_ID, PO.CurrentSet AS cr,gP.tTest_id AS Header,convert(float,Po.Results) as Results from tPhos_Line_Operator PO
inner join tPhos_Line_Parameter pp
on PO.tPhos_Line_Parameter_id = PP.id
INNER JOIN tGroup_Parameter GP
on pp.tGroup_Parameter_id = gp.id
where PP.tPhosline_id=134)P
on T.tGroup_id = P.G_ID
AND T.CurrentSet = p.cr
PIVOT ( MAX(p.Results) For Header IN ([4],[23],[24])) AS pvt
Anyone know how to get the DateTimeStamp and the pivot record?
Which mean i will only have 4 columns in this case.
Currently i need to select * from.
I'm sorry still a junior in query.
Thanks in advance.
sample data could go here:
sample of expected result:
dateTime | currentset | tGroup_id | G_ID | cr | 4 | 23 | 24 |
2015-03-11 07:00:24.313 1 69 69 1 8.36 10 14.4
2015-03-12 00:31:58.257 2 69 69 2 9.12 8 14.4
I am making a guess. It appears that you want to "pivot" some results so you get to see these side by side instead of across multiple rows.
While PIVOT has been added into many SQL implementations, it is not the only way to achieve pivoted data nor is it always the best or easiest way to do it. Here is an old fashioned "pivot" that uses a set of case expressions and 'GROUP BY':
SELECT
PO.tGroup_id AS G_ID
, PO.CurrentSet AS cr
, MAX( datetimestamp ) AS datetimestamp
, MAX( CASE WHEN gP.tTest_id = 4 THEN CONVERT(float, Po.Results) END ) AS Results4
, MAX( CASE WHEN gP.tTest_id = 23 THEN CONVERT(float, Po.Results) END ) AS Results23
, MAX( CASE WHEN gP.tTest_id = 24 THEN CONVERT(float, Po.Results) END ) AS Results24
FROM tPhos_Line_Operator PO
INNER JOIN tPhos_Line_Parameter pp ON PO.tPhos_Line_Parameter_id = PP.id
INNER JOIN tGroup_Parameter GP ON pp.tGroup_Parameter_id = gp.id
WHERE PP.tPhosline_id = 134
GROUP BY
PO.currentSet
, PO.tGroup_id
Because you haven't supplied sample data I don't know the details but hopefully you can bend this to suit your data.
This is an alternative approach using the PIVOT operator but this also relies on using MAX() OVER(). One complication for using the PIVOT operator here is that you require a maximum datetime value as well as pivoted rows which is complex using the inbuilt pivot operator. I believe that complexity can be overcome by the MaxDateTime column seen below:
SELECT
MaxDateTime , CR, G_ID, [4], [23], [24]
FROM (
SELECT
PO.tGroup_id AS G_ID
, PO.CurrentSet AS cr
, gP.tTest_id AS Header
, MAX( PO.datetimestamp ) OVER (PARTITION BY PO.tGroup_id, PO.CurrentSet, gP.tTest_id) AS MaxDateTime
, CONVERT( float, Po.Results ) AS Results
FROM tPhos_Line_Operator PO
INNER JOIN tPhos_Line_Parameter pp ON PO.tPhos_Line_Parameter_id = PP.id
INNER JOIN tGroup_Parameter GP ON pp.tGroup_Parameter_id = gp.id
WHERE PP.tPhosline_id = 134
) AS sourve_tbl
PIVOT (MAX( Results ) FOR Header IN ([4], [23], [24])
) AS pvt_tbl
;
Yes your existing query is wrong.
I hv tried to correct it.
;With CTE as
(
select Max(datetimestamp)as datetimestamp, currentSet, tGroup_id
from tPhos_Line_Operator
group by currentSet, tGroup_id
)
Select * from
( SELECT PO.tGroup_id AS G_ID, PO.CurrentSet AS cr,gP.tTest_id AS Header
,convert(float,Po.Results) as Results
,T.*
from tPhos_Line_Operator PO
inner join tPhos_Line_Parameter pp
on PO.tPhos_Line_Parameter_id = PP.id
INNER JOIN tGroup_Parameter GP
on pp.tGroup_Parameter_id = gp.id
left join CTE T on T.tGroup_id = P.PO.tGroup_id
AND T.CurrentSet = PO.CurrentSet
where PP.tPhosline_id=134)tbl
PIVOT ( MAX(p.Results) For Header IN ([4],[23],[24])) AS pvt

SQL add Sum to existing query (Cannot perform an aggregate function on an expression containing an aggregate or a subquery.)

I have a existing working SQL query I would like to now GroupBy but am getting the error: Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
Explanation of my scenario:
My main table (dbo.DataLog) contains 3 columns, TimestampUTC, MeterTagId, Data.
Data typically comes in at 15 minute intervals and I have many meters (MeterTagId) for each
TimestampUTC. The Data column is a float and this is a totalised value. i.e. to get the actual value for a meter period I need to subtract the last value from the current one. Before now I have successfully been querying individual meters but now I am trying to group by time and show a sum/total of all meters for that time.
Original working non summed query:
SELECT
l.TimestampUTC
-- Get this value minus the last value
,(SELECT (l.[Data] -
( SELECT TOP 1 l2.Data
FROM [DataLog] l2
WHERE l2.MeterTagId = l.MeterTagId
AND l2.TimestampUTC < l.TimestampUTC
ORDER BY l2.TimestampUTC DESC)
)
) AS Actual_Value
FROM [dbo].[DataLog] l
INNER JOIN [dbo].MeterTags t on t.MeterTagId = l.MeterTagId
INNER JOIN [dbo].Meters m on m.MeterId = t.MeterId
INNER JOIN [dbo].GroupsMeters gm on gm.MeterId = m.MeterId
INNER JOIN [dbo].Groups g on g.GroupId = gm.GroupId
LEFT OUTER JOIN dbo.Units u on u.UnitId = t.UnitId
WHERE (#MeterId is null OR M.MeterId in (#MeterId))
AND (#MeterTagId is null OR t.MeterTagId in (#MeterTagId))
AND (#StartDate is null OR l.TimestampUTC >= #StartDate)
AND (#EndDate is null OR l.TimestampUTC <= #EndDate)
AND (#GroupId is null OR g.GroupId in (#GroupId))
.
My attempt to to get the summary:
SELECT
l.TimestampUTC
-- Get this value minus the last value
, (SELECT SUM(l.[Data] -
( SELECT TOP 1 l2.Data
FROM [DataLog] l2
WHERE l2.MeterTagId = l.MeterTagId
AND l2.TimestampUTC < l.TimestampUTC
ORDER BY l2.TimestampUTC DESC)
)
)AS Actual_Value
FROM [dbo].[DataLog] l
INNER JOIN [dbo].MeterTags t on t.MeterTagId = l.MeterTagId
INNER JOIN [dbo].Meters m on m.MeterId = t.MeterId
INNER JOIN [dbo].GroupsMeters gm on gm.MeterId = m.MeterId
INNER JOIN [dbo].Groups g on g.GroupId = gm.GroupId
LEFT OUTER JOIN dbo.Units u on u.UnitId = t.UnitId
WHERE (#MeterId is null OR M.MeterId in (#MeterId))
AND (#MeterTagId is null OR t.MeterTagId in (#MeterTagId))
AND (#StartDate is null OR l.TimestampUTC >= #StartDate)
AND (#EndDate is null OR l.TimestampUTC <= #EndDate)
AND (#GroupId is null OR g.GroupId in (#GroupId))
AND t.Name ='Real Energy Net'
GROUP BY l.TimestampUTC
I have read other posts on here but can't get my head around the logic required, I imagine/hope this is something sql dev's come across regularly? Thanks!
OK, I worked it out, it's simple really. Hopefully this explanation helps someone else with the same issue in the future.
SELECT
myTable.TimestampUTC
, SUM(myTable.Actual_Value) as [Actual Value]
FROM
(
--My original query
) AS myTable
GROUP BY myTable.TimestampUTC

SQL Union Query

SELECT pv.PropertyID, COUNT(pv.VisitID) AS InitialVisit
FROM tblPAppointments pa INNER JOIN tblPropertyVisit pv ON pv.AppID = pa.AppID
WHERE pv.Status = 0
GROUP BY pv.PropertyID
UNION ALL
SELECT jv.PropertyID, COUNT(jv.JobVistID) AS JobVisit
FROM tblPAppointments pa INNER JOIN tblJobVisits jv ON jv.AppID = pa.AppID
WHERE jv.VisitStatus = 1
GROUP BY jv.PropertyID
I need to get InitialVisit count and JobVisit count in two separate columns.above query returns just two columns (PropertyID,InitialVisit).
Use a NULL as a placeholder for the column that there won't be any output for:
SELECT pv.PropertyID,
COUNT(pv.VisitID) AS InitialVisit,
NULL AS jobvisit
FROM tblPAppointments pa
JOIN tblPropertyVisit pv ON pv.AppID = pa.AppID
WHERE pv.Status = 0
GROUP BY pv.PropertyID
UNION ALL
SELECT jv.PropertyID,
NULL AS initialvisit,
COUNT(jv.JobVistID) AS JobVisit
FROM tblPAppointments pa
JOIN tblJobVisits jv ON jv.AppID = pa.AppID
WHERE jv.VisitStatus = 1
GROUP BY jv.PropertyID
This will return three columns. The column alias is necessary in the first query, but not in the second -- I aliased both to make it clear what is happening.
Be aware that using NULL like this in SQL Server will require you to use CAST/CONVERT on the NULL for data types other than INT because SQL Server defaults the NULL to an INT data type (as odd as that is).
An alternate query that doesn't use UNION:
SELECT x.propertyid,
COUNT(y.visitid) AS initialvisit,
COUNT(z.jobvisitid) AS jobvisit
FROM (SELECT pv.propertyid
FROM TBLPROPERTYVISIT pv
WHERE EXISTS (SELECT NULL
FROM TBLAPPOINTMENTS a
WHERE a.appid = pv.appid)
UNION
SELECT jv.propertyid
FROM TBLJOBVISIT jv
WHERE EXISTS (SELECT NULL
FROM TBLAPPOINTMENTS a
WHERE a.appid = jv.appid)) x
LEFT JOIN TBLPROPERTYVISIT y ON y.propertyid = x.propertyid
LEFT JOIN TBLJOBVISIT z ON z.propertyid = x.propertyid
GROUP BY x.propertyid
No need for a UNION at all. And you don't use tblPAppointments either
Edited to allow for no rows in one of the tables. Still one row output though
SELECT
ISNULL(pv2.PropertyID, jv2.PropertyID),
ISNULL(pv2.InitialVisit, 0),
ISNULL(jv2.JobVisit, 0)
FROM
(
SELECT pv.PropertyID, COUNT(pv.VisitID) AS InitialVisit
FROM tblPropertyVisit pv
WHERE pv.Status = 0
GROUP BY pv.PropertyID
) pv2
FULL OUTER JOIN
(
SELECT jv.PropertyID, COUNT(jv.JobVistID) AS JobVisit
FROM tblJobVisits jv
WHERE jv.VisitStatus = 1
GROUP BY jv.PropertyID
) jv2 ON pv2.PropertyID = jv2.PropertyID