From e983d4496c0c4c32b6bed3dae63db91a7dc1b8ba Mon Sep 17 00:00:00 2001 From: StephenCWills Date: Mon, 21 Sep 2026 11:43:43 -0400 Subject: [PATCH 1/2] Fix location and asset group filters in event search --- PQBrowser/Controllers/OpenXDAController.cs | 111 ++++++++++++++++----- 1 file changed, 84 insertions(+), 27 deletions(-) diff --git a/PQBrowser/Controllers/OpenXDAController.cs b/PQBrowser/Controllers/OpenXDAController.cs index 2c064f28..efe3fcba 100644 --- a/PQBrowser/Controllers/OpenXDAController.cs +++ b/PQBrowser/Controllers/OpenXDAController.cs @@ -247,10 +247,20 @@ public DataTable GetEventSearchData([FromBody] EventSearchPostData postData) if (postData.eventID is not null) return GetSingleEventSearchData(postData.eventID.GetValueOrDefault(), fullSortColumn, sortOrder, resultCount); - string locationList = postData.locationIDs.Length > 0 ? string.Join(',', postData.locationIDs) : "Meter.LocationID"; - string meterList = postData.meterIDs.Length > 0 ? string.Join(',', postData.meterIDs) : "MeterID"; - string assetList = postData.assetIDs.Length > 0 ? string.Join(',', postData.assetIDs) : "AssetID"; - string assetGroupList = postData.groupIDs.Length > 0 ? string.Join(',', postData.groupIDs) : "AssetGroupID"; + string locationList = postData.locationIDs.Length > 0 ? string.Join(',', postData.locationIDs) : null; + string meterLocationList = locationList ?? "Meter.LocationID"; + string assetLocationList = locationList ?? "AssetLocation.LocationID"; + + string assetGroupList = postData.groupIDs.Length > 0 ? string.Join(',', postData.groupIDs) : null; + string meterAssetGroupList = assetGroupList ?? "MeterAssetGroup.AssetGroupID"; + string assetAssetGroupList = assetGroupList ?? "AssetAssetGroup.AssetGroupID"; + + // These stub values will force IsAtLocation = 1 and IsInGroup = 1 respectively + object locationStub = postData.locationIDs.Length == 0 ? 0 : DBNull.Value; + object assetGroupStub = postData.groupIDs.Length == 0 ? 0 : DBNull.Value; + + string meterList = postData.meterIDs.Length > 0 ? string.Join(',', postData.meterIDs) : "Meter.ID"; + string assetList = postData.assetIDs.Length > 0 ? string.Join(',', postData.assetIDs) : "Asset.ID"; string eventTypeList = postData.typeIDs.Length > 0 ? string.Join(',', postData.typeIDs) : "NULL"; string phaseList = GetPhaseList(postData); @@ -309,19 +319,44 @@ public DataTable GetEventSearchData([FromBody] EventSearchPostData postData) string query = $$""" - SELECT DISTINCT MeterID ID + SELECT DISTINCT + Meter.ID, + CASE WHEN Meter.LocationID IN ({{meterLocationList}}) + THEN 1 + ELSE 0 + END IsAtLocation, + CASE WHEN COALESCE(MeterAssetGroup.ID, {3}) IS NOT NULL + THEN 1 + ELSE 0 + END IsInGroup INTO #meterFilter - FROM MeterAssetGroup - WHERE - MeterID IN ({{meterList}}) AND - AssetGroupID IN ({{assetGroupList}}) + FROM + Meter LEFT OUTER JOIN + MeterAssetGroup ON + MeterAssetGroup.MeterID = Meter.ID AND + MeterAssetGroup.AssetGroupID IN ({{meterAssetGroupList}}) + WHERE Meter.ID IN ({{meterList}}) - SELECT DISTINCT AssetID ID + SELECT DISTINCT + Asset.ID, + CASE WHEN COALESCE(AssetLocation.ID, {2}) IS NOT NULL + THEN 1 + ELSE 0 + END IsAtLocation, + CASE WHEN COALESCE(AssetAssetGroup.ID, {3}) IS NOT NULL + THEN 1 + ELSE 0 + END IsInGroup INTO #assetFilter - FROM AssetAssetGroup - WHERE - AssetID IN ({{assetList}}) AND - AssetGroupID IN ({{assetGroupList}}) + FROM + Asset LEFT OUTER JOIN + AssetLocation ON + AssetLocation.AssetID = Asset.ID AND + AssetLocation.LocationID IN ({{assetLocationList}}) LEFT OUTER JOIN + AssetAssetGroup ON + AssetAssetGroup.AssetID = Asset.ID AND + AssetAssetGroup.AssetGroupID IN ({{assetAssetGroupList}}) + WHERE Asset.ID IN ({{assetList}}) SELECT TOP {{resultCount}} Event.ID, @@ -338,7 +373,14 @@ EventType.Name NOT IN ('Fault', 'RecloseIntoFault', 'Sag', 'Swell', 'Transient', Event.EventTypeID IN ({{eventTypeList}}) AND Event.MeterID IN (SELECT ID FROM #meterFilter) AND Event.AssetID IN (SELECT ID FROM #assetFilter) AND - Meter.LocationID IN ({{locationList}}) + ( + Event.MeterID IN (SELECT ID FROM #meterFilter WHERE IsAtLocation <> 0) OR + Event.AssetID IN (SELECT ID FROM #assetFilter WHERE IsAtLocation <> 0) + ) AND + ( + Event.MeterID IN (SELECT ID FROM #meterFilter WHERE IsInGroup <> 0) OR + Event.AssetID IN (SELECT ID FROM #assetFilter WHERE IsInGroup <> 0) + ) {{eventOrdering}} CREATE TABLE #disturbanceFilter @@ -372,24 +414,31 @@ Event JOIN Disturbance ON Disturbance.EventID = Event.ID JOIN EventType ON Disturbance.EventTypeID = EventType.ID JOIN Phase ON Disturbance.PhaseID = Phase.ID JOIN - {{curveTable}} ON StandardMagDurCurve.ID = {2} + {{curveTable}} ON StandardMagDurCurve.ID = {4} {{disturbanceJoin}} WHERE Event.StartTime BETWEEN DATEADD({{timeWindowUnits}}, -{0}, {1}) AND DATEADD({{timeWindowUnits}}, {0}, {1}) AND Event.MeterID IN (SELECT ID FROM #meterFilter) AND Event.AssetID IN (SELECT ID FROM #assetFilter) AND - Meter.LocationID IN ({{locationList}}) AND + ( + Event.MeterID IN (SELECT ID FROM #meterFilter WHERE IsAtLocation <> 0) OR + Event.AssetID IN (SELECT ID FROM #assetFilter WHERE IsAtLocation <> 0) + ) AND + ( + Event.MeterID IN (SELECT ID FROM #meterFilter WHERE IsInGroup <> 0) OR + Event.AssetID IN (SELECT ID FROM #assetFilter WHERE IsInGroup <> 0) + ) AND Disturbance.EventTypeID IN ({{eventTypeList}}) AND Phase.Name IN ({{phaseList}}) AND - ({4} IS NULL OR Disturbance.DurationSeconds >= {4}) AND - ({5} IS NULL OR Disturbance.DurationSeconds <= {5}) AND - ({6} IS NULL OR EventType.Name <> 'Sag' OR Disturbance.PerUnitMagnitude >= {6}) AND - ({7} IS NULL OR EventType.Name <> 'Sag' OR Disturbance.PerUnitMagnitude <= {7}) AND - ({8} IS NULL OR EventType.Name <> 'Swell' OR Disturbance.PerUnitMagnitude >= {8}) AND - ({9} IS NULL OR EventType.Name <> 'Swell' OR Disturbance.PerUnitMagnitude <= {9}) AND - ({10} IS NULL OR EventType.Name <> 'Transient' OR Disturbance.PerUnitMagnitude >= {10}) AND - ({11} IS NULL OR EventType.Name <> 'Transient' OR Disturbance.PerUnitMagnitude <= {11}) AND - (StandardMagDurCurve.Area IS NULL OR StandardMagDurCurve.Area.STContains(geometry::Point(Disturbance.DurationSeconds, Disturbance.PerUnitMagnitude, 0)) = {3}) + ({6} IS NULL OR Disturbance.DurationSeconds >= {6}) AND + ({7} IS NULL OR Disturbance.DurationSeconds <= {7}) AND + ({8} IS NULL OR EventType.Name <> 'Sag' OR Disturbance.PerUnitMagnitude >= {8}) AND + ({9} IS NULL OR EventType.Name <> 'Sag' OR Disturbance.PerUnitMagnitude <= {9}) AND + ({10} IS NULL OR EventType.Name <> 'Swell' OR Disturbance.PerUnitMagnitude >= {10}) AND + ({11} IS NULL OR EventType.Name <> 'Swell' OR Disturbance.PerUnitMagnitude <= {11}) AND + ({12} IS NULL OR EventType.Name <> 'Transient' OR Disturbance.PerUnitMagnitude >= {12}) AND + ({13} IS NULL OR EventType.Name <> 'Transient' OR Disturbance.PerUnitMagnitude <= {13}) AND + (StandardMagDurCurve.Area IS NULL OR StandardMagDurCurve.Area.STContains(geometry::Point(Disturbance.DurationSeconds, Disturbance.PerUnitMagnitude, 0)) = {5}) {{disturbanceOrdering}} ) DisturbanceFilter JOIN Disturbance ON Disturbance.EventID = DisturbanceFilter.EventID @@ -412,7 +461,14 @@ EventType.Name IN ('Fault', 'RecloseIntoFault') AND Event.EventTypeID IN ({{eventTypeList}}) AND Event.MeterID IN (SELECT ID FROM #meterFilter) AND Event.AssetID IN (SELECT ID FROM #assetFilter) AND - Meter.LocationID IN ({{locationList}}) AND + ( + Event.MeterID IN (SELECT ID FROM #meterFilter WHERE IsAtLocation <> 0) OR + Event.AssetID IN (SELECT ID FROM #assetFilter WHERE IsAtLocation <> 0) + ) AND + ( + Event.MeterID IN (SELECT ID FROM #meterFilter WHERE IsInGroup <> 0) OR + Event.AssetID IN (SELECT ID FROM #assetFilter WHERE IsInGroup <> 0) + ) AND FaultSummary.FaultType IN ({{phaseList}}) AND FaultSummary.IsSelectedAlgorithm <> 0 AND FaultSummary.IsValid <> 0 AND @@ -545,6 +601,7 @@ ORDER BY {{sortColumn}} {{sortOrder}} return connection.RetrieveData(query, windowSize, searchTime, + locationStub, assetGroupStub, curveID, curveFilter, durationMin, durationMax, sagMin, sagMax, From e3a5c4a9fb63d4b8a4dbf8a6457501fd5f5a1e3d Mon Sep 17 00:00:00 2001 From: StephenCWills Date: Mon, 21 Sep 2026 11:44:08 -0400 Subject: [PATCH 2/2] Fix disturbance-related filters in event search --- PQBrowser/Controllers/OpenXDAController.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/PQBrowser/Controllers/OpenXDAController.cs b/PQBrowser/Controllers/OpenXDAController.cs index efe3fcba..b716ae4e 100644 --- a/PQBrowser/Controllers/OpenXDAController.cs +++ b/PQBrowser/Controllers/OpenXDAController.cs @@ -441,7 +441,22 @@ Phase.Name IN ({{phaseList}}) AND (StandardMagDurCurve.Area IS NULL OR StandardMagDurCurve.Area.STContains(geometry::Point(Disturbance.DurationSeconds, Disturbance.PerUnitMagnitude, 0)) = {5}) {{disturbanceOrdering}} ) DisturbanceFilter JOIN - Disturbance ON Disturbance.EventID = DisturbanceFilter.EventID + Disturbance ON Disturbance.EventID = DisturbanceFilter.EventID JOIN + EventType ON Disturbance.EventTypeID = EventType.ID JOIN + Phase ON Disturbance.PhaseID = Phase.ID JOIN + {{curveTable}} ON StandardMagDurCurve.ID = {4} + WHERE + Disturbance.EventTypeID IN ({{eventTypeList}}) AND + Phase.Name IN ({{phaseList}}) AND + ({6} IS NULL OR Disturbance.DurationSeconds >= {6}) AND + ({7} IS NULL OR Disturbance.DurationSeconds <= {7}) AND + ({8} IS NULL OR EventType.Name <> 'Sag' OR Disturbance.PerUnitMagnitude >= {8}) AND + ({9} IS NULL OR EventType.Name <> 'Sag' OR Disturbance.PerUnitMagnitude <= {9}) AND + ({10} IS NULL OR EventType.Name <> 'Swell' OR Disturbance.PerUnitMagnitude >= {10}) AND + ({11} IS NULL OR EventType.Name <> 'Swell' OR Disturbance.PerUnitMagnitude <= {11}) AND + ({12} IS NULL OR EventType.Name <> 'Transient' OR Disturbance.PerUnitMagnitude >= {12}) AND + ({13} IS NULL OR EventType.Name <> 'Transient' OR Disturbance.PerUnitMagnitude <= {13}) AND + (StandardMagDurCurve.Area IS NULL OR StandardMagDurCurve.Area.STContains(geometry::Point(Disturbance.DurationSeconds, Disturbance.PerUnitMagnitude, 0)) = {5}) SELECT TOP {{resultCount}} FaultSummary.ID,