You can now use ST_ClusterDBSCAN for this purpose, with a minimum cluster size of 1 and a distance parameter of 0. This will cluster objects that are no more than a specified distance away from each other -- in this case, touching, as distance = 0 -- and, as it is a window function, you can easily get back the IDs of any geometries in each cluster as an array, using the array_agg function. Then all you need to do is select those clusters which only have one ID in the returned array that represents the ids per cluster, using the array_length function. Clusters of size one are your detached buildings.
Modifying the example query from the docs somewhat:
WITH clusters (cid, ids_in_cluster) AS (
SELECT cid, array_agg(building_id) AS ids_in_cluster
ST_ClusterDBSCAN(geom, eps := 0, minpoints := 1) OVER () AS cid
GROUP BY cid
SELECT cid, ids_in_cluster
WHERE array_length(ids_in_cluster, 1) = 1;
This version of ST_ClusterDBSCAN, with distance 0, and minpoints 1, is essentially identical to ST_ClusterIntersecting, which returns a set of geometries, which makes it more painful to infer which IDs/geometries are in each cluster. As DBSCAN is a window function, it allows you more flexibility with the results.
There is nothing wrong with the approach in your question. However, as it involves a spatial self-join, it is likely to be slower than the clustering approach.