5

我在 MS SQL Server 2005 数据库中有两个表,父表和子表,其中父表可能与许多子记录相关。[Child.parent_id] 与 [parent.id] 相关。子表也有列 [foo] 我需要带回父表中 [child.foo] 与一对多参数中的每一个匹配的所有记录。例如,我想要所有 [child.foo] 值为“fizz”且 [child.foo] 值为“buzz”的父记录。我尝试了以下查询,但它返回的记录仅匹配一个。

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')
4

4 回答 4

9

我相信你想要这样的东西。

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。

于 2010-01-29T21:03:50.247 回答
9

这将返回所有具有 [至少] 一个带有“fizz” foo 的孩子和 [至少] 一个带有“buzz” foo 的孩子的父记录。这是我认为这个问题所需要的。

此外,虽然可能是次优的,但这个查询是通用的,因为它可以与大多数 SQL 实现一起工作,而不仅仅是更现代的支持 CTE、子查询和相关构造的支持。

   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'

编辑
既然乔尔波特已经在他的答案中修复了这个查询,我们可能同意他的方法比上面列出的查询有几个优点(请给他一些 +reps)。尤其是:

  • 当我们添加或删除列 foo 的目标值时,查询的结构不会改变。
  • 查询可能更容易优化[由服务器本身]
  • 查询的结构允许它处理过滤器定义的变化。例如,我们可以查询所有有孩子的父母,例如 foo 的 5 个可能值中有 2 个存在。

以下是 Joel 的查询,稍作修改,以显示如何将其扩展为超过 2 个 foo 值。

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 ...  
于 2010-01-29T21:06:19.443 回答
1

我想分享乔尔出色答案的这个简单概括。这里的想法是能够将任意“目标”子表作为表值参数或拆分分隔字符串传递到过程中。虽然这很好,但如果有一个使用 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
于 2016-07-12T17:31:46.767 回答
-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')
)
于 2010-01-29T21:05:29.337 回答