5

MS SQL Server 2005データベースには、親と子の2つのテーブルがあり、親は多くの子レコードに関連付けられている可能性があります。[Child.parent_id]は[parent.id]に関連しています。子テーブルにも列[foo]があります。親テーブルのすべてのレコードを戻す必要があります。[child.foo]は1対多のパラメーターのそれぞれで一致します。たとえば、[child.foo]の値が「fizz」で[child.foo]の値が「buzz」のすべての親レコードが必要です。以下のクエリを試しましたが、1つだけに一致するレコードが返されます。

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

Id1のみを返します。

于 2010-01-29T21:03:50.247 に答える
9

これにより、[少なくとも]1つの子が'fizz' fooであり、[少なくとも]1つの子が'buzz'fooであるすべての親レコードが返されます。質問ではこれが必要だと思います。

また、このクエリは潜在的に最適ではありませんが、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が回答のクエリを修正したので、彼のアプローチには上記のクエリに比べていくつかの利点があることにおそらく同意します(+ repsをいくつか与えてください)。特に:

  • 列fooのターゲット値を追加または削除しても、クエリの構造は変更されません。
  • クエリはおそらく[サーバー自体によって]より簡単に最適化されます
  • クエリの構造により、フィルターの定義のバリエーションを処理できます。たとえば、fooの5つの可能な値のうちの2つが存在するように、子を持つすべての親にクエリを実行できます。

以下は、2つ以上のfoo値に対してどのように拡張できるかを示すために、わずかに変更されたJoelのクエリです。

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

Joelの優れた答えのこの単純な一般化を共有したいと思いました。ここでの考え方は、「ターゲット」の子の任意のテーブルを、テーブル値パラメーターまたは分割区切り文字列としてプロシージャに渡すことができるようにすることです。これは素晴らしいことですが、INの代わりにLIKEを使用して一致する同様のクエリがあることも素晴らしいでしょう。

--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 に答える