SQL需求:当所有子节点DestinationId都传入时查询父节点SourceId
嘿,我帮你整理了一个完全符合需求的解决方案,从定义表类型到存储过程实现,再到测试调用,一步步来:
第一步:定义表类型
因为存储过程需要接收表类型的DestinationId集合作为参数,所以我们先创建对应的表类型:
-- 定义表类型,用于接收DestinationId集合 CREATE TYPE dbo.DestinationIdList AS TABLE ( DestinationId INT NOT NULL PRIMARY KEY );
第二步:实现存储过程
核心思路很简单:先算出每个SourceId关联的所有DestinationId总数,再统计传入集合中匹配该SourceId的目标ID数量,当两者完全相等时,就说明这个SourceId的所有目标ID都在传入集合里了,这就是我们要返回的结果。
CREATE PROCEDURE dbo.GetMatchingSourceIds @DestinationIds dbo.DestinationIdList READONLY AS BEGIN SET NOCOUNT ON; -- 统计每个SourceId对应的DestinationId总数 WITH SourceDestinationCounts AS ( SELECT SourceId, COUNT(DISTINCT DestinationId) AS TotalDestinations FROM YourTableName -- 记得替换成你的实际表名 GROUP BY SourceId ), -- 统计每个SourceId在传入集合中匹配的DestinationId数量 MatchedCounts AS ( SELECT sd.SourceId, COUNT(DISTINCT sd.DestinationId) AS MatchedDestinations FROM YourTableName sd INNER JOIN @DestinationIds di ON sd.DestinationId = di.DestinationId GROUP BY sd.SourceId ) -- 筛选出总数量等于匹配数量的SourceId SELECT sdc.SourceId FROM SourceDestinationCounts sdc LEFT JOIN MatchedCounts mc ON sdc.SourceId = mc.SourceId WHERE mc.MatchedDestinations = sdc.TotalDestinations; END;
第三步:测试调用
比如你要传入(2,3,4,5,7,12)这个集合,可以这样操作:
-- 声明表变量并填充传入的DestinationId DECLARE @InputDestinations dbo.DestinationIdList; INSERT INTO @InputDestinations (DestinationId) VALUES (2),(3),(4),(5),(7),(12); -- 执行存储过程 EXEC dbo.GetMatchingSourceIds @DestinationIds = @InputDestinations;
执行后会返回SourceId = 1,完全符合你给出的示例需求——6和11因为只有部分目标ID在传入集合里,会被自动排除。
内容的提问来源于stack exchange,提问作者siddharth




