1

こんにちはみんな私はこのように機能するテーブルリレーションを持っています(レガシー)

Aには多くのBがあり、Bには多くのCがあります。AにはCもたくさんあります

現在、すべてのB(単純にするためにBのId)を特定のA(Idによって)およびCのサブセットであるCのコレクションを持つ任意のBにマップするのに役立つSQLを思い付くのに問題があります。そのA。

私は特に第2部のためにまともなSQLを思い付くことができず、それをどのように行うことができるかについてのヒントや提案を得ることができるかどうか疑問に思っていました。

ありがとう

編集:

Table A

Id     |..
------------
 1     |..




Table B

Id     |..
--------------
2      |..

Table A_B_rel 

A_id  |    B_id
-----------------
1     |     2

Cは奇妙なテーブルです。C(単一列)のデータは、実際にはAとBの2 relテーブルに複製されているだけなので、次のようになります。

Table B_C_Table

B_Id| C_Value
-----------------
2   | 'Somevalue' 

Table A_C_Table

A_Id| C_Value
-------------
1   |    'SomeValue'

そのため、C_Valueが特定のA_C_ValueのサブセットであるBを探しています。

4

3 に答える 3

1

おそらくこれはあなたが探しているものです:

SELECT B_id
FROM A_B_rel
WHERE A_id = <A ID>

UNION

SELECT a.B_Id
FROM B_C_Table a
LEFT JOIN A_C_Table b ON a.C_Value = b.C_Value AND b.A_Id = <A ID>
GROUP BY a.B_Id
HAVING COUNT(CASE WHEN b.A_Id IS NULL THEN 1 END) = 0

最初に、特定の(A IDの入力パラメーターである)にマップされたSELECTすべての'を取得し、次に、その結​​果セットに、'のセット全体が'のサブセットにある追加の'を追加します。特に(ここでも、入力パラメーターです)。BA<A ID>BC_ValueC_ValueA<A ID>

于 2012-07-03T04:21:48.283 に答える
1

はい、問題の2番目の部分は少し注意が必要です。B_C_Table一方では、特定のIDがどこにあるかのサブセットがA_C_Tableあります。A_ID

B_C_Tableここで、外部結合を使用すると、次の行で一致しない行を確認できますA_C_Table

SELECT *
FROM B_C_Table bc
  LEFT JOIN A_C_Table ac ON bc.C_Value = ac.C_Value AND ac.A_ID = @A_ID

後者の場合、一致しない行を除外するため、をではなく句にac.A_ID = @A_ID入れることが重要であることに注意してください。これは、必要なものではありません。ONWHERE@A_ID

次のステップ(最終クエリを達成するため)は、行をグループ化し、行Bをカウントすることです。次に、行の総数と一致する行の数の両方を計算します。

SELECT
  bc.B_ID,
  COUNT(*)       AS TotalCount,
  COUNT(ac.A_ID) AS MatchCount
FROM B_C_Table bc
  LEFT JOIN A_C_Table ac ON bc.C_Value = ac.C_Value AND ac.A_ID = @A_ID
GROUP BY bc.B_ID

ご覧のとおり、一致をカウントするには、ac.A_ID値をカウントするだけです。一致しない場合は、対応する列がカウントされるNULLため、カウントされません。そして、実際にの一部の行B_C_Tableがのサブセットのどの行とも一致しない場合、との異なるA_C_Tableが表示されます。TotalCountMatchCount

そして、それは論理的に私たちを最終ステップに導きます:それらのカウントを比較します。(もちろん、値を取得できれば、それらを比較することもできます。)しかしWHERE、もちろん、集計関数はで許可されていないため、句ではありませんWHERE。これは、集約された値も含めて、グループ化HAVINGされた行の値を比較するために使用される句です。それで...

SELECT
  bc.B_ID,
  COUNT(*)       AS TotalCount,
  COUNT(ac.A_ID) AS MatchCount
FROM B_C_Table bc
  LEFT JOIN A_C_Table ac ON bc.C_Value = ac.C_Value AND ac.A_ID = @A_ID
GROUP BY bc.B_ID
HAVING COUNT(*) = COUNT(ac.A_ID)

B_IDもちろん、カウント値は実際には必要ありません。それらをドロップすると、上記のクエリを次のクエリから選択してUNIONすることができますA_B_rel

SELECT B_ID
FROM A_B_rel
WHERE A_ID = @A_ID

UNION

SELECT bc.B_ID
FROM B_C_Table bc
  LEFT JOIN A_C_Table ac ON bc.C_Value = ac.C_Value AND ac.A_ID = @A_ID
GROUP BY bc.B_ID
HAVING COUNT(*) = COUNT(ac.A_ID)
于 2012-07-03T07:53:53.310 に答える
1

二重否定の観点から考える必要があるように聞こえます。つまり、一致するA_Cを持たないB_Cは存在しないはずです(少なくとも1つのB_Cが必要だと思います)。

だから、次のようなものを試してください

select B.B_id
from Table_B B 
where exists (select 1 from B_C_Table BC
                  where BC.B_id = B.B_id)
  and not exists (select 1 from B_C_Table BC
                  where BC.B_id = B.B_id
                    and not exists(select 1 from B_C_Table AC
                                   join A_B_Rel ABR on AC.A_id = ABR.A_id
                                   where ABR.B_id = B.B_id
                                     and BC.C_Value = AC.C_Value))
于 2012-07-03T16:23:16.017 に答える