'Combining SQL Server queries for speed

I have two tables, one of items that require regular inspection and one of inspection reports for those items.

Items can be marked as "not available for inspection" if the engineer couldn't see them for whatever reason.

I need to display the list of items, showing the last actual inspection date for each item. If the last actual inspection for the item was not the same as the last visit date (ie last attempted inspection), this needs to be highlighted.

Here's what I have currently:

Tables and columns:

Items
ID, Name, etc...

ReportItems
ReportID, ItemID, InspectionDate, NotAvailable

Commence dodgy pseudocode:

SELECT * FROM Items

' then loop through that to display the data:
For each itemDataRow

  ' Get last actual date
  datatable1 = SELECT TOP 1 ReportID, InspectionDate FROM ReportItems WHERE ItemID = itemDataRow(ID) AND NotAvailable = 0 ORDER BY InspectionDate DESC

  ' Get last attempted date
  datatable2 = SELECT TOP 1 ReportID FROM ReportItems WHERE ItemID = itemDataRow(ID) ORDER BY InspectionDate DESC

  ' Check if they are the same
  itemWasNotAvailableAtLastVisit = datatable1(ReportID) <> datatable2(ReportID)

  ' add row to list to display, showing datatable1(InspectionDate), highlighted if itemWasNotAvailableAtLastVisit == true

End loop

The trouble is that this means 2 extra database queries for each item when populating the data, which is slowing things down considerably, especially on longer lists.

How can I optimise this, ideally into a single fast query?

I have tried subqueries like this but it's very slow:

SELECT ID, Name, (
SELECT TOP 1 InspectionDate FROM ReportItems WHERE ItemID = Items.ID AND Available = 0 ORDER BY InspectionDate DESC
) AS LastInspection,
(
SELECT TOP 1 InspectionDate FROM ReportItems WHERE ItemID = Items.ID ORDER BY InspectionDate DESC
) AS LastVisit
 FROM Items

Sample data:

Items

ID | Name
---------
1  | Crane
2  | Tractor
3  | Forklift

ReportItems

ReportID | VisitID | ItemID | InspectionDate | NotAvailable
----------------------------------------------------------------
1        | 1       | 1      | 2022-04-20     | 0
2        | 1       | 2      | 2022-04-20     | 1
3        | 1       | 3      | 2022-04-20     | 0
4        | 2       | 1      | 2022-03-15     | 0
5        | 2       | 2      | 2022-03-15     | 0
6        | 2       | 3      | 2022-03-15     | 0

Desired results:

Crane, last inspection was 2022-04-20
Tractor, last inspection was **2022-03-15** (NB This is not the last visit date) 
Forklift, last inspection was 2022-04-20



Solution 1:[1]

Based on your example query you can probably join/group/max as follows:

SELECT ID, [Name]
    , MAX(CASE WHEN Available = 0 THEN InspectionDate END) AS LastInspection
    , MAX(InspectionDate) AS LastVisit
FROM Items I
JOIN ReportItems RI on RI.ItemID = I.ID
GROUP BY I.ID;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dale K