2010-08-11 72 views
12

我有兩個表tabData和tabDataDetail。 我想從家長表所有IDDATA(PK)(tabData)有在兒童表只行(tabDataDetail,FK是fiData)有:SQL查詢:在子表中的EXISTS

  • fiActionCode = 11單獨 或
  • fiactionCode = 11和fiActionCode = 34

任何其他組合無效。如何獲得他們?

我所沒有成功嘗試(慢,讓我也有行只 fiActioncode 34):

alt text http://www.bilder-hochladen.net/files/4709-l0.jpg

感謝您的時間。


編輯:感謝所有爲他們的答案。現在我不幸沒有足夠的時間來檢查哪一個是最好的或工作。我標出了第一個工作人員的答案。

編輯2:我認爲標記的答案確實是最高效和緊湊的解決方案。

編輯3:Codesleuth的答案很有趣,因爲它只返回行,而不是隻有一個單一的fiActionCode = 11。很難看到,因爲它只有20個tabDataDetail行有41524189個總共有兩個行。無論如何,這不是我問過的100%,而是我正在尋找的東西。

+0

從來沒有提到輸出中需要哪些列。它僅僅是tabData列還是來自tabDataDetail所需的任何數據? – Thomas 2010-08-11 15:26:41

+0

它只是我感興趣的主鍵(idData),應該按照(如果需要)進行分組(並排序)。但要檢查結果,最好還有fiActionCode。 – 2010-08-11 15:45:34

回答

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

謝謝。但是,這也給了我在Childtable中只有34作爲fiActionCode的行。這些應該被排除在外。 – 2010-08-11 15:10:17

+0

@Tim - 修正。只需要額外檢查以確保fiActionCode = 11存在。 – Thomas 2010-08-11 15:15:43

+0

PK是idData和tablename是tabData但除此之外它似乎工作(我不知道爲什麼)。我得到了40萬行,因此很難檢查。 – 2010-08-11 15:26:28

1

編輯:Apols - 我明白你的意思與子行。這不是特別有效。還要感謝Lieven的數據。

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) 
) 
+0

也可以。 – 2010-08-11 15:33:21

4

推理

  1. LEFT OUTER JOIN排除所有IDDATA的有11個或34
  2. HAVING排除不同的所有IDDATA的是只有有34
  3. 剩餘記錄的ID(應)滿足所有限制

測試數據

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 
+0

謝謝,但我得到了幾個「多部分標識符」d.idData「無法綁定。'和'曖昧列名' – 2010-08-11 15:15:50

+0

您是否刪除了@?查詢在我的系統上運行時沒有問題。 – 2010-08-11 15:19:02

+0

也可以(有點慢)。謝謝 – 2010-08-12 08:17:38

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 
+0

也正確結果。這種方法(「無效檢查」)對我來說是新的。 – 2010-08-12 08:13:39

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)

由於這裏只有1子查詢(和它是一個COUNT而不是非常慢的NOT EXISTS),這會創建一個非常整齊的執行計劃,如果遇到速度問題,這應該會有所幫助。

+0

@CodeSleuth,不要提及它。根據性能分析儀的成本爲我的解決方案的24%,你的32%。如果這種情況持續下去,我很有興趣知道真實世界的情況。 – 2010-08-11 15:16:48

+0

我沒有真正看過這個問題或任何細節的答案,但作爲一般性觀點,'NOT EXISTS'在SQL Server中比'COUNT(*)'更有效,因爲它實現了反半連接。它只需檢查是否存在匹配的行。不計算所有匹配的。 – 2010-08-11 15:21:43

+0

@Lieven:費用是什麼?只是子查詢?對不起,我好像'NOT IN'混合了'NOT EXISTS' - 我錯了,在我的答案中,表現實際上比COUNT好。我會編輯它。乾杯! – Codesleuth 2010-08-11 15:25:29

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 
+0

這也適用(當改變'SELECT ... FRO M idData i'到'SELECT idData FROM tabData i')。謝謝。 – 2010-08-12 08:03:15