SQL返回具有某些关联并排除其他关联的记录

SQL返回具有某些关联并排除其他关联的记录,sql,Sql,我有以下疑问: SELECT * FROM "AssetGroups" ag INNER JOIN "AssetGroupsTags" agt ON ag."Id" = agt."AssetGroupId" WHERE agt."TagId" IN (63, 77) AND agt."TagId" NOT IN (97); 这将返回ID为1031的记录。运行此查询时: SELECT "TagId" FROM "AssetGroupsTags" WHERE "AssetGroupId"

我有以下疑问:

SELECT * FROM "AssetGroups" ag
  INNER JOIN "AssetGroupsTags" agt ON ag."Id" = agt."AssetGroupId"
  WHERE  agt."TagId" IN (63, 77) AND agt."TagId" NOT IN (97);
这将返回ID为1031的记录。运行此查询时:

SELECT "TagId" FROM "AssetGroupsTags" WHERE "AssetGroupId" = 1031;
它返回97、63、27。我认为
以及
不在
中会排除记录1031,但这并没有发生


需要明确的是:我想返回所有标记ID为63或77,但标记ID为97的记录。

假设我正确理解了您的问题,这里有一个选项使用
不存在

select *
from assetgroups ag
    join assetgroupstags agt on ag.id = agt.assetgroupid
where agt.tagid in (63, 77) 
    and not exists (
        select 1
        from assetgroupstags agt2 
        where agt.assetgroupid = agt2.assetgroupid and agt2.tagid = 97
    )

这将返回任何标记ID为63或77的
AssetGroup
,但不返回97的
AssetGroup

我只使用聚合:

SELECT agt."AssetGroupId"
FROM "AssetGroupsTags" agt 
GROUP BY agt."AssetGroupId"
HAVING SUM(CASE WHEN agt."TagId" IN (63, 77) THEN 1 ELSE 0 END) > 0 AND
       SUM(CASE WHEN agt."TagId" IN (97) THEN 1 ELSE 0 END) = 0;

如果您需要组id之外的其他字段,则可以将它们加入。

TagId
是字符串中以逗号分隔的列表值吗?如果是这样,你就不能在中使用
。你在使用什么数据库管理系统?@Nick这不是字符串,而是返回的值列表。@eltiare,你能在这里粘贴一些当前场景中的数据示例吗?如果我理解正确,你可以使用self-join。是的,我认为这是最干净的方法。很高兴它有帮助。还有其他选择,比如使用带有
null
检查的
外部联接
,但我认为这是最明确的。@sgedes,从性能角度看,哪一个是好的,要么是
自联接
,要么是使用
不存在
?@GauravGenius--我相信这有点取决于数据库,但一般来说,
存在
将在第一次匹配时短路,其中
外部连接
将迭代所有匹配。话虽如此,在这种情况下,
外部连接
将只有一条记录,因此我认为它们将产生几乎相同的执行计划。这里有一个潜在的相关帖子: