簡體   English   中英

SQL Query用於獲取具有子記錄列表的父表的記錄

[英]SQL Query to get records of parent table that have a list of child records

我在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')

這將返回所有父記錄,其中[至少]一個孩子有'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的目標值時,查詢的結構不會更改。
  • 查詢可能更容易優化[由服務器本身]
  • 查詢的結構允許它處理過濾器定義的變化。 例如,我們可以查詢所有有孩子的父母,例如說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 ...  

我相信你想要這樣的東西。

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

我想分享這個簡單概括的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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM