Thanks; I'm now working on doing this in-database. For the specific case of being able to find photos that are only in one category, the below seems to work; if a photo is only in category "bride", it also gets the computed category "bride⇔1". As soon as it is added to another category that doesn't have the character "⇔" in it, the computed category "bride⇔1" disappears. So selecting category "bride⇔1" will show photos with only the bride.
The below SQL does this (in a non-normalized way, just for ease of looking at stuff for the time being); hopefully I'll be able to move existing tables to new "tablename_real" tables, and have the tables be views via the
SQLite updateable views workaround. I think this should be transparent to XnView MP unless XnView MP explicitly checks to make sure the schema is what it thinks it should be. It should be possible to just silently ignore the user trying to manually add / remove / rename / etc a photo to a computed category.
If this does work, I think it should be possible to cover ⇔[2...n] cases via CTEs (common table expressions), but I'm horrible at recursion so I'd probably put that off for a while; the "one and only one person" case covers 90% of my needs.
~~
SELECT Images.ImageID AS ImageID, Tags.TagID + 1000000 AS TagID, Tags.Label || '⇔1' AS Label, Tags.ParentID AS ParentID, Tags.ID AS ID, Tags.Hidden AS Hidden, Tags.Description AS Description, Tags.Shortcut AS Shortcut
FROM Tags
JOIN TagsTree on TagsTree.TagID = Tags.TagID
JOIN Images on Images.ImageID = TagsTree.ImageID
JOIN Folders on Folders.FolderID = Images.FolderID
WHERE Tags.Label NOT LIKE '%⇔1%'
GROUP BY Images.ImageID
HAVING count(Images.ImageID) = 1
UNION
SELECT Images.ImageID AS ImageID, Tags.TagID AS TagID, Tags.Label AS Label, Tags.ParentID AS ParentID, Tags.ID AS ID, Tags.Hidden AS Hidden, Tags.Description AS Description, Tags.Shortcut AS Shortcut
FROM Tags
JOIN TagsTree on TagsTree.TagID = Tags.TagID
JOIN Images on Images.ImageID = TagsTree.ImageID
JOIN Folders on Folders.FolderID = Images.FolderID
ORDER BY Images.ImageID