我有两张包含以下数据的表格:
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;
答案 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
它基本上会将父母与任何具有等于' 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'