SQL - child必须包含所有指定的值

时间:2014-05-18 11:54:54

标签: sql sql-server tsql

我有两张包含以下数据的表格:

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中选择所有行,其中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;

3 个答案:

答案 0 :(得分:5)

我不确定"更正确",但是使用GROUP BY / HAVING的简单JOIN将在没有子查询的情况下完成;

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'是两个可能的值),则返回父级。

答案 1 :(得分: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在父表中)

编写Joachim Isaksson查询的另一种方法是将子属性的检查移到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

答案 2 :(得分: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'
相关问题