12

tabDataとtabDataDetailの2つのテーブルがあります。親テーブル(tabData)のすべてのidData(PK)で、子テーブル(tabDataDetail、FKはfiData)に行のみが含まれている必要があります。

  • fiActionCode=11単独または
  • fiactionCode=11およびfiActionCode=34

その他の組み合わせは無効です。それらを取得する方法は?

私が成功せずに試したこと(遅く、fiActioncode 34しかない行も表示されます):

代替テキスト
(出典:bilder-hochladen.net

御時間ありがとうございます。


編集:彼らの答えをありがとう。残念ながら、どれが最適であるか、まったく機能していないかを確認するのに十分な時間がありません。私は最初に機能するものを回答としてマークしました。

EDIT2:マークされた答えは本当に最も効率的でコンパクトなソリューションだと思います。

EDIT3:Codesleuthの答えは興味深いものです。なぜなら、fiActionCode=11が1つしかないよりも行だけが返されるからです。合計で41524189の20個のtabDataDetail-rowsotにのみ当てはまるため、わかりにくいです。2つある行です。とにかく、それは私が求めていたものではなく、むしろ私が探していたものではありませんでした。

4

6 に答える 6

6
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の行が存在することを確認することです。2番目のチェックは、最初に不要な行のセットを定義することによって機能します。fiActionCode = 11または34以外のものは必要ありません。これは不要なアイテムのセットであるため、そのセットに存在しないものを検索します。

于 2010-08-11T15:00:00.560 に答える
4

推論

  1. LEFT OUTER JOIN11 または 34 とは異なる ID を持つすべての idData を除外します
  2. HAVING34のみを持つすべての idData を除外します
  3. 残りのレコードはすべての制約を満たしている (はずである)

テストデータ

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
于 2010-08-11T15:02:18.530 に答える
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)
 )
于 2010-08-11T15:00:23.680 に答える
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
于 2010-08-11T15:04:53.143 に答える
1

これは、私が考えるデータを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
于 2010-08-11T15:35:03.963 に答える
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 行)

ここにサブクエリが 1 つしかない (そして、それがCOUNTvery-slow ではなく であるNOT EXISTS) と、速度に問題がある場合に役立つ非常にきちんとした実行プランが作成されます。

于 2010-08-11T15:13:11.273 に答える