我有两个表tabData和tabDataDetail。 我希望来自Parent-Table(tabData)的所有idData(PK)在Child-Table(tabDataDetail,FK是fiData)中具有仅行,并且:
任何其他组合无效。如何获得它们?
我尝试过没有成功的事情(很慢并且还提供了仅 fiActioncode 34的行):
alt text http://www.bilder-hochladen.net/files/4709-l0.jpg
谢谢你的时间。
编辑:感谢大家的回答。现在我很遗憾没有足够的时间来检查哪一个是最好的还是有效的。我将第一个工作标记为答案。
EDIT2:我认为明确的答案确实是最有效和最紧凑的解决方案。
EDIT3:Codesleuth的答案很有趣,因为它只返回行而不是只有一个fiActionCode = 11。很难看到,因为它的唯一真正的20个tabDataDetail-rows总共41524189行有两个。无论如何,这不是我所要求的100%,而是我正在寻找的东西。
答案 0 :(得分:5)
Select ...
From tabData As T1
Where Exists (
Select 1
From tabDataDetail As TDD1
Where TDD1.fiData = T1.idData
And TDD1.fiactionCode = 11
)
And Not Exists (
Select 1
From tabDataDetail As TDD1
Where TDD1.fiData = T1.idData
And TDD1.fiactionCode Not In(11,34)
)
要扩展我的逻辑,首先检查(更正)是为了确保存在fiActionCode = 11的行。第二项检查首先定义我们不想要的行集。除了fiActionCode = 11或34之外,我们不需要任何其他内容。因为这是我们不想要的项目集,我们会搜索该集合中不存在的任何内容。
答案 1 :(得分:4)
<强>推理强>
LEFT OUTER JOIN
排除ID不同于11或34 HAVING
排除仅有34 测试数据
DECLARE @tabData TABLE (idData INTEGER)
DECLARE @tabDataDetail TABLE (fiData INTEGER, fiActionCode INTEGER)
INSERT INTO @tabData VALUES (1)
INSERT INTO @tabData VALUES (2)
INSERT INTO @tabData VALUES (3)
INSERT INTO @tabData VALUES (4)
INSERT INTO @tabData VALUES (5)
/* Only idData 1 & 2 should be returned */
INSERT INTO @tabDataDetail VALUES (1, 11)
INSERT INTO @tabDataDetail VALUES (2, 11)
INSERT INTO @tabDataDetail VALUES (2, 34)
INSERT INTO @tabDataDetail VALUES (3, 99)
INSERT INTO @tabDataDetail VALUES (4, 11)
INSERT INTO @tabDataDetail VALUES (4, 99)
INSERT INTO @tabDataDetail VALUES (5, 34)
<强>查询强>
SELECT *
FROM @tabData d
INNER JOIN @tabDataDetail dd ON dd.fiData = d.idData
INNER JOIN (
SELECT idData
FROM @tabData d
INNER JOIN @tabDataDetail dd ON dd.fiData = d.idData
LEFT OUTER JOIN (
SELECT fiData
FROM @tabDataDetail
WHERE fiActionCode NOT IN (11, 34)
) exclude ON exclude.fiData = d.idData
WHERE exclude.fiData IS NULL
GROUP BY
idData
HAVING MIN(fiActionCode) = 11
) include ON include.idData = d.idData
答案 2 :(得分:1)
编辑:Apols - 我明白了你对子行的意思。这不是特别有效。还要感谢列文的数据。
SELECT idData FROM
tabData td
WHERE EXISTS
(
SELECT 1
FROM tabDataDetail tdd
WHERE tdd.fiData = td.idData AND fiActionCode = 11
)
AND NOT EXISTS
(
SELECT 1
FROM tabDataDetail tdd
WHERE tdd.fiData = td.idData AND fiActionCode <> 11
)
UNION
SELECT idData
FROM tabData td
WHERE EXISTS
(
SELECT 1
FROM tabDataDetail tdd
WHERE tdd.fiData = td.idData AND fiActionCode = 11
)
AND EXISTS
(
SELECT 1
FROM tabDataDetail tdd
WHERE tdd.fiData = td.idData AND fiActionCode = 34
)
AND NOT EXISTS
(
SELECT 1
FROM tabDataDetail tdd
WHERE tdd.fiData = td.idData AND fiActionCode NOT IN (11, 34)
)
答案 3 :(得分:1)
根据对其他答案的评论中的澄清编辑我的答案。
select td.idData
from tabData td
left join tabDataDetail tdd
on td.idData = tdd.fiData
and tdd.fiActionCode = 11
left join tabDataDetail tdd2
on td.idData = tdd2.fiData
and tdd2.fiActionCode = 34
left join tabDataDetail tdd3
on td.idData = tdd3.fiData
and tdd3.fiActionCode not in (11,34)
where (tdd.fiData is not null
or (tdd.fiData is not null and tdd2.fiData is not null))
and tdd3.fiData is null
group by td.idData
答案 4 :(得分:1)
感谢@ Lieven对数据代码进行测试:
DECLARE @tabData TABLE (idData INTEGER)
DECLARE @tabDataDetail TABLE (idDataDetail int IDENTITY(1,1),
fiData INTEGER, fiActionCode INTEGER)
INSERT INTO @tabData VALUES (1)
INSERT INTO @tabData VALUES (2)
INSERT INTO @tabData VALUES (3)
INSERT INTO @tabData VALUES (4)
INSERT INTO @tabData VALUES (5)
/* Only idData 1 & 2 should be returned */
INSERT INTO @tabDataDetail (fiData,fiActionCode) VALUES (1, 11)
INSERT INTO @tabDataDetail (fiData,fiActionCode) VALUES (2, 11)
INSERT INTO @tabDataDetail (fiData,fiActionCode) VALUES (2, 34)
INSERT INTO @tabDataDetail (fiData,fiActionCode) VALUES (3, 99)
INSERT INTO @tabDataDetail (fiData,fiActionCode) VALUES (4, 11)
INSERT INTO @tabDataDetail (fiData,fiActionCode) VALUES (4, 99)
INSERT INTO @tabDataDetail (fiData,fiActionCode) VALUES (5, 34)
查询:
SELECT td.idData
FROM @tabData td
INNER JOIN @tabDataDetail tdd ON td.idData = tdd.fiData
WHERE tdd.fiActionCode = 11 -- check 11 exists
AND NOT EXISTS ( SELECT * FROM @tabDataDetail WHERE fiData = td.idData
AND idDataDetail <> tdd.idDataDetail )
-- ensures *only* 11 exists (0 results from subquery)
UNION
SELECT td.idData
FROM @tabData td
INNER JOIN @tabDataDetail tdd1 ON td.idData = tdd1.fiData
INNER JOIN @tabDataDetail tdd2 ON td.idData = tdd2.fiData
WHERE tdd1.fiActionCode = 11 -- check 11 exists
AND tdd2.fiActionCode = 34 -- check 34 exists
返回:
idData ----------- 1 2 (2 row(s) affected)
这里只有一个子查询(而且它是一个COUNT
而不是一个非常慢的NOT EXISTS
)这会创建一个非常简洁的执行计划,如果你遇到速度问题,应该会有所帮助。 / p>
答案 5 :(得分:1)
这是通过我认为的数据传递它。
这取决于数据分布是否优于进行2次单独查找。
WITH matches AS
(
SELECT fiData
FROM tabDataDetail
GROUP BY fiData
HAVING COUNT(CASE WHEN fiactionCode = 11 THEN 1 END) > 0
AND COUNT(CASE WHEN fiactionCode NOT IN (11,34) THEN 1 END) = 0
)
SELECT ...
FROM idData i
JOIN matches m
ON m.fiData = i.idData