2014-05-18 32 views
0

我有两个表具有以下数据:SQL - 孩子必须包含所有指定的值

Test_parent

parent_id title 
------------------ 
1 Parent1 
2 Parent2 
3 Parent3 
4 Parent4 

Test_child

child_id parent_id property 
------------------------------------ 
1 1 A 
2 2 A 
3 2 B 
4 3 A 
5 3 C 
6 4 A 

我要选择从表test_parent所有行其中父母包含具有(BOTH)属性A和B(因此这将与parent_id = 2一起记录)的儿童

这是我写到目前为止最好的解决办法:

select * 
from test_parent p 
where (select COUNT(property) 
     from test_child c 
     where p.parent_id = c.parent_id and c.property in ('A', 'B')) = 2 

有没有什么更“正确”的方式?

非常感谢!

这是对象的完整脚本:

CREATE TABLE [dbo].[test_parent](
    [parent_id] [int] IDENTITY(1,1) NOT NULL, 
    [title] [nvarchar](50) NOT NULL, 
CONSTRAINT [PK_test_parent] PRIMARY KEY CLUSTERED 
([parent_id])) 
GO 

CREATE TABLE [dbo].[test_child](
    [child_id] [int] IDENTITY(1,1) NOT NULL, 
    [parent_id] [int] NOT NULL, 
    [property] [nvarchar](10) NOT NULL, 
CONSTRAINT [PK_test_child] PRIMARY KEY CLUSTERED 
([child_id])) 
GO 

ALTER TABLE [dbo].[test_child] WITH CHECK ADD CONSTRAINT [FK_test_child_test_child] FOREIGN KEY([parent_id]) 
REFERENCES [dbo].[test_parent] ([parent_id]) 
GO 

ALTER TABLE [dbo].[test_child] CHECK CONSTRAINT [FK_test_child_test_child] 
GO 

SET IDENTITY_INSERT [dbo].[test_parent] ON; 
INSERT INTO [dbo].[test_parent]([parent_id], [title]) 
SELECT 1, N'Parent1' UNION ALL 
SELECT 2, N'Parent2' UNION ALL 
SELECT 3, N'Parent3' UNION ALL 
SELECT 4, N'Parent4' 

SET IDENTITY_INSERT [dbo].[test_parent] OFF; 
GO 

SET IDENTITY_INSERT [dbo].[test_child] ON; 

INSERT INTO [dbo].[test_child]([child_id], [parent_id], [property]) 
SELECT 1, 1, N'A' UNION ALL 
SELECT 2, 2, N'A' UNION ALL 
SELECT 3, 2, N'B' UNION ALL 
SELECT 4, 3, N'A' UNION ALL 
SELECT 5, 3, N'C' UNION ALL 
SELECT 6, 4, N'A' 
GO 

SET IDENTITY_INSERT [dbo].[test_child] OFF; 
+0

可能[只选择并且只有特定记录的副本acle](http://stackoverflow.com/questions/23608118/select-only-and-only-specific-record-in-oracle) – Serpiton

回答

4

我不知道“更正确”,但一个简单的使用JOIN GROUP BY/HAVING会做没有一个子查询;

SELECT test_parent.parent_id, test_parent.title 
FROM test_parent 
JOIN test_child ON test_child.parent_id=test_parent.parent_id 
AND test_child.property IN ('A','B') 
GROUP BY test_parent.parent_id, test_parent.title 
HAVING COUNT(DISTINCT test_child.property)=2 

An SQLfiddle to test with

它将基本上与任何具有属性等于“A”或“B”的孩子的父母连接,并由父行对其进行计数,并计算孩子上不同的值property。如果它等于2('A'和'B'是两个可能的值),则返回父项。

+0

我试过两种。 与GROUP BY和HAVING的联接比子查询执行得好10%。 顺便说一下,计数对于获得正确结果至关重要。 –

0

你可以试试这个。我相信它会表现得更好,但你应该检查执行计划来检查这一点。

SELECT distinct tp.title 
    FROM test_parent tp 
    INNER JOIN test_child ca on tp.parent_id=ca.parent_id and ca.property='A' 
    INNER JOIN test_child cb on ca.parent_id=cb.parent_id and cb.property='B' 
1

的问题

select * 
from test_parent p 
where 2 = (select COUNT(property) 
      from test_child c 
      where p.parent_id = c.parent_id 
       and c.property in ('A', 'B')) 

查询有一个小问题:如果有两个孩子,都与“A”或两者与“B”家长会显示在结果中,这与所述的要求不同。 它也不会显示有两个以上孩子的父母,即使他们只有“A”和“B”的属性,例如,如果我们添加的行

child_id | parent_id | property 
     7 |   5 |  A 
     8 |   5 |  B 
     9 |   5 |  A 

到test_child父的数据5将不会在结果(指出,5是在父表)

另一种方式来写约阿希姆伊萨克森的查询是对儿童性移动检查到HAVING条款

SELECT tp.id, tp.title 
FROM test_parent tp 
     INNER JOIN test_child tc ON tp.parent_id = tc.parent_id 
GROUP BY tp.id, tp.title 
HAVING COUNT(DISTINCT tp.property) = 2 
    AND SUM(CASE WHEN tp.property IN ('A', 'B') THEN 0 ELSE 1 END) = 0 
相关问题