"WHERE (subquery) IN (subquery)"可以吗?
Is "WHERE (subquery) IN (subquery)" possible?
我们需要 select 只使用连接到机器的标签的测试。
标签对测试来说是多对多的。 (TagTest 关联 table)
标签对机器来说是多对多的。 (TagMachine 关联 table)
示例:
如果测试有标签 [A,B,C] 而机器有 [A,B,D] 则不应选择测试,因为它的标签不是机器标签的子集。
如果测试有标签 [A,B] 并且机器有 [A,B,D] 则应该包含测试。
如果测试没有标签,则应始终包含它。
像这样的构造应该可以工作:
SELECT *
FROM Test te
WHERE
(SELECT tt.tagId
FROM TagTest tt
WHERE tt.testId = te.Id)
IN
(SELECT tm.tagId
FROM TagMachine tm
WHERE tm.machineId = 123)
但是这种查询可能吗?如果没有,怎么可能达到预期的效果?
如果第一个 returns 是标量值(即单行),则此查询是可能的。因此,仅使用 IN
无法实现您想做的事情。一种处理此问题的 Postres 方法使用数组
WHERE (SELECT ARRAY_AGG(tt.tagId)
FROM TagTest tt
WHERE tt.testId = te.Id
) <@
(SELECT ARRAY_AGG(tm.tagId)
FROM TagMachine tm
WHERE tm.machineId = 123
)
IN()
自己做不到。您可以制作两个 CTE 并将它们连接在一起,但这仍然有点棘手。
相反,让我们来扭转这个问题。我们可以查找 缺少任何一个必需标签 的记录,而不是查找匹配 所有 良好标签的记录。从问题的第一个示例([A,B,C]
vs [A,B,D]
)中,我们正在寻找带有 C
标记的 TestTag
记录。一旦我们有了这些信息,我们就可以在子查询中使用它来排除所有 Test
记录,其中 Id
出现在这些结果中。
所以首先要做的是使用排除连接来查找缺少相应 TagMachine
记录的 TestTag
结果:
SELECT tt.testId, tt.tagId
FROM TestTag tt
LEFT JOIN TagMachine tm ON tm.machineId = 123 AND tm.tagId = tt.tagId
WHERE tm.tagId IS NULL
上述查询结果中任何 testId
的存在使得 Test
与 Id
不合格 ... 但是我们确实需要 所有其他 Test
记录。所以现在只需将其限制为 DISTINCT testId
并将其用作任何排除连接、NOT IN() 或 NOT EXISTS() 中的子查询。随你挑:
SELECT *
FROM Tests
WHERE Id NOT IN (
--identify tests hat are missing at least one tag
SELECT DISTINCT tt.testId
FROM TestTag tt
LEFT JOIN TagMachine tm ON tm.machineId = 123 AND tm.tagId = tt.tagId
WHERE tm.tagId IS NULL)
我们需要 select 只使用连接到机器的标签的测试。
标签对测试来说是多对多的。 (TagTest 关联 table)
标签对机器来说是多对多的。 (TagMachine 关联 table)
示例:
如果测试有标签 [A,B,C] 而机器有 [A,B,D] 则不应选择测试,因为它的标签不是机器标签的子集。
如果测试有标签 [A,B] 并且机器有 [A,B,D] 则应该包含测试。
如果测试没有标签,则应始终包含它。
像这样的构造应该可以工作:
SELECT *
FROM Test te
WHERE
(SELECT tt.tagId
FROM TagTest tt
WHERE tt.testId = te.Id)
IN
(SELECT tm.tagId
FROM TagMachine tm
WHERE tm.machineId = 123)
但是这种查询可能吗?如果没有,怎么可能达到预期的效果?
如果第一个 returns 是标量值(即单行),则此查询是可能的。因此,仅使用 IN
无法实现您想做的事情。一种处理此问题的 Postres 方法使用数组
WHERE (SELECT ARRAY_AGG(tt.tagId)
FROM TagTest tt
WHERE tt.testId = te.Id
) <@
(SELECT ARRAY_AGG(tm.tagId)
FROM TagMachine tm
WHERE tm.machineId = 123
)
IN()
自己做不到。您可以制作两个 CTE 并将它们连接在一起,但这仍然有点棘手。
相反,让我们来扭转这个问题。我们可以查找 缺少任何一个必需标签 的记录,而不是查找匹配 所有 良好标签的记录。从问题的第一个示例([A,B,C]
vs [A,B,D]
)中,我们正在寻找带有 C
标记的 TestTag
记录。一旦我们有了这些信息,我们就可以在子查询中使用它来排除所有 Test
记录,其中 Id
出现在这些结果中。
所以首先要做的是使用排除连接来查找缺少相应 TagMachine
记录的 TestTag
结果:
SELECT tt.testId, tt.tagId
FROM TestTag tt
LEFT JOIN TagMachine tm ON tm.machineId = 123 AND tm.tagId = tt.tagId
WHERE tm.tagId IS NULL
上述查询结果中任何 testId
的存在使得 Test
与 Id
不合格 ... 但是我们确实需要 所有其他 Test
记录。所以现在只需将其限制为 DISTINCT testId
并将其用作任何排除连接、NOT IN() 或 NOT EXISTS() 中的子查询。随你挑:
SELECT *
FROM Tests
WHERE Id NOT IN (
--identify tests hat are missing at least one tag
SELECT DISTINCT tt.testId
FROM TestTag tt
LEFT JOIN TagMachine tm ON tm.machineId = 123 AND tm.tagId = tt.tagId
WHERE tm.tagId IS NULL)