SQL查询以获取具有子记录列表的父表的记录
我在MS SQL Server 2005数据库中有两个表,即父表和子表,其中父表可能与许多子记录相关。[Child.parent\u id]与[parent.id]相关。子表也有列[foo],我需要返回父表中[child.foo]与一对多参数中的每个参数匹配的所有记录。例如,我希望所有父记录的[child.foo]值为'fizz',[child.foo]值为'buzz' 我尝试了下面的查询,但它返回的记录只与一个匹配SQL查询以获取具有子记录列表的父表的记录,sql,sql-server-2005,hierarchical-data,Sql,Sql Server 2005,Hierarchical Data,我在MS SQL Server 2005数据库中有两个表,即父表和子表,其中父表可能与许多子记录相关。[Child.parent\u id]与[parent.id]相关。子表也有列[foo],我需要返回父表中[child.foo]与一对多参数中的每个参数匹配的所有记录。例如,我希望所有父记录的[child.foo]值为'fizz',[child.foo]值为'buzz' 我尝试了下面的查询,但它返回的记录只与一个匹配 SELECT Parent.ID FROM Paren
SELECT Parent.ID
FROM Parent
INNER JOIN Child ON Parent.ID = Child.parent_id
WHERE (Child.foo = 'fizz')
UNION ALL
SELECT Parent_1.ID
FROM Parent AS Parent_1
INNER JOIN Child AS Child_1 ON Parent_1.ID = Child_1.parent_id
WHERE (Child_1.foo = 'buzz')
我相信你想要这样的东西
Select
Parent.Id
From Parent
inner join Child on Parent.Id = child.parent_id
Where
Child.foo = 'fizz' or Child.foo = 'buzz'
Group By
Parent.Id
Having
count(distinct Child.foo) > 1
以下是测试脚本:
Create Table #parent ( id int )
Create Table #child ( parent_id int, foo varchar(32) )
insert into #parent (id) values (1)
insert into #parent (id) values (2)
insert into #parent (id) values (3)
insert into #child (parent_id, foo) values (1, 'buzz')
insert into #child (parent_id, foo) values (2, 'buzz')
insert into #child (parent_id, foo) values (3, 'buzz')
insert into #child (parent_id, foo) values (1, 'fizz')
Select
#parent.Id
From #parent
inner join #child on #parent.id = #child.parent_id
Where
#child.foo = 'fizz' or #child.foo = 'buzz'
Group By
#parent.Id
Having
count(distinct #child.foo) > 1
drop table #parent
drop table #child
仅返回Id 1。这将得到您想要的结果:
SELECT p.ID
FROM Parent p
WHERE EXISTS
(
SELECT 1 FROM Child c WHERE c.parent_id = p.ID AND c.foo IN ('fizz','buzz')
)
这将返回所有父记录,其中[至少]有一个子项具有“fizz”foo,[至少]有一个子项具有“buzz”foo。我认为这是问题所需要的 此外,虽然该查询可能是次优的,但从某种意义上讲,它是通用的,可以用于大多数SQL实现,而不仅仅是支持CTE、子查询和相关构造的更现代的SQL实现
SELECT DISTINCT Parent.ID
FROM Parent
JOIN Child C1 ON Parent.ID = C1.parent_Id
JOIN Child C2 ON Parent.ID = C2.parent_id
WHERE C1.foo = 'fizz'
AND C2.foo = 'buzz'
编辑:既然Joel Potter在他的回答中修正了这个问题,我们可能同意他的方法比上面列出的问题有几个优点(请给他几次+重复)。特别是:
- 当我们为foo列添加或删除目标值时,查询的结构不会改变
- 查询可能更容易[由服务器本身]优化
- 查询的结构允许它处理过滤器定义的变化。例如,我们可以查询所有有孩子的父母,比如说5个可能的foo值中有2个存在
SELECT Parent.Id
FROM Parent
INNER JOIN Child on Parent.Id = child.parent_id
WHERE Child.foo IN ('fizz', 'buzz') -- or say, ... IN ('fizz', 'buzz', 'bang', 'dong')
GROUP BY Parent.Id
HAVING COUNT(DISTINCT Child.foo) = 2 -- or 4 ...
我想和大家分享一下Joel的优秀答案的简单概括。这里的想法是能够将包含“目标”子级的任意表作为表值参数或拆分分隔字符串传递到过程中。虽然这很好,但是如果有一个类似的查询,使用LIKE而不是IN进行匹配也很好
--Parents whose children contain a subset of children
--setup
create table #parent ( id int )
create table #child ( parent_id int, foo varchar(32) )
insert into #parent (id) values (1)
insert into #parent (id) values (2)
insert into #parent (id) values (3)
insert into #child (parent_id, foo) values (1, 'buzz')
insert into #child (parent_id, foo) values (1, 'buzz')
insert into #child (parent_id, foo) values (1, 'fizz')
insert into #child (parent_id, foo) values (2, 'buzz')
insert into #child (parent_id, foo) values (2, 'fizz')
insert into #child (parent_id, foo) values (2, 'bang')
insert into #child (parent_id, foo) values (3, 'buzz')
--create in calling procedure
declare @tblTargets table (strTarget varchar(10))
insert into @tblTargets (strTarget) values ('fizz')
insert into @tblTargets (strTarget) values ('buzz')
--select query to be called in procedure;
-- pass @tblTargets in as TVP, or create from delimited string via splitter function
select #parent.id --returns 1 and 2
from #parent
inner join #child on #parent.id = #child.parent_id
where #child.foo in (select strTarget from @tblTargets)
group by #parent.id
having count(distinct #child.foo) = (select COUNT(*) from @tblTargets)
--cleanup
drop table #parent
drop table #child
我已经指定了数据库。我只是假设解决方案与数据库无关,但我不需要。递归CTE是ANSI标准,但实现滞后-只有3个dbs支持
:Oracle、SQL Server和DB2。虽然问题是模棱两可的,但我认为OP希望家长既有“嘶嘶”的,又有“嗡嗡”的孩子。上面的查询将返回具有“fizz”或“buzz”孩子的父母。啊,你可能是对的。因此,我将投票表决你的答案。例如,如果给定的家长有两个(或更多)foo值为'fizz'@mjv:你是对的,那么这个查询将失败。将count(*)
替换为count(distinct Child.foo)
以更正该错误。马上开始。我编辑了我的答案,以指向您现在已修复的解决方案,因为我发现它更通用,更[自动]优化。然而,这种类型查询的查询计划在很大程度上取决于特定的SQL实现和数据的特定统计配置文件。@mjv:我不确定分组与联接的性能。如果你有基准,那将是伟大的看到。不过,关于特定的RDBMS是一个因素,您可能是对的。