2011-01-22 22 views
0

私は....(多くを持っている)「エリア」「資産」(多くを持っている)SQL:オプションの外部キーが

「フロア」、そして

私は以下の表を持っています」タスク "テーブル。

"タスク"は、 "エリア"または "資産"のいずれかに割り当てることができます。だからareaIdとassetIdという名前の "Task"テーブルに2つのカラムがあり、そのうちの1つに値が必要です。

第1質問:特定のフロアで発生したすべてのタスクをクエリするにはどうすればよいですか?

2番目の質問:参照整合性を強制するにはどうすればよいですか?

3番目の質問:このアプローチは推奨されていますか?どんな提案も歓迎しない。与えられたすべての答えを

多くのおかげで、

ETFairfax

+0

「エリア」を特定の種類の資産としてモデル化することを検討しましたか? 「エリア」と「アセット」は全く違っていますか(あなたがやっている仕事を含む)ですか?それとも、同じように違いますか? –

答えて

2

第一の質問:

SELECT 
    distinct t.TaskID 
FROM 
    Floor f 
     inner join 
    Area a 
     on 
      f.FloorID = a.FloorID 
     left join 
    Asset ast 
     on 
      a.AreaID = ast.AreaID 
     inner join 
    Task t 
     on 
      t.AreaID = a.AreaID or 
      t.AssetID = ast.AssetID 
WHERE 
    f.FloorID = @FloorID 

は、あなたが構築しようとしているクエリの形状を与える必要があります。 (もちろん、あなたが実際にあなたがすでにFloorIDを持っている場合、フロアテーブルを照会する必要はありません)

第二の質問:

CREATE TABLE Task (
    TaskID int not null, 
    AreaID int null, 
    AssetID int null, 
    constraint PK_Task PRIMARY KEY (TaskID), 
    constraint FK_Task_Area FOREIGN KEY (AreaID) references Area (AreaID), 
    constraint FK_Task_Asset FOREIGN KEY (AssetID) references Asset (AssetID), 
    constraint CK_Task_OneNonNull CHECK (
     (AreaID is null and AssetID is not null) or 
     (AssetID is null and AreaID is not null)) 
) 

あるいは、あなたはユニークなを追加し、エリアIDがnullでないことができます(AreaID、AssetID)のAssetテーブルの制約を確認し、Assetテーブルへの外部キーを両方のカラムで参照するようにします。これにより、AssetIDが指定されている場合、正しいAreaIDに属するAssetにリンクされます。

これがすべて使用されようとしている方法を知らずに言うのは難しい:エリアIDは、タスク

第三の質問に常にあります場合、これはまた、Q1への答えを簡素化します。私はそれがのun-合理的なアプローチだとは思わない。

+0

すばらしい!あなたの迅速かつ簡潔な答えをありがとう。 – ETFairfax

0

は質問3で始まるのをみましょう、これは有効なアプローチですか?それが現実をモデル化するかどうかです。フロア、エリア、およびアセットがプロパティとは異なり、一般的なプロパティよりも異なるプロパティを持ち、それらの操作が異なる傾向にある場合、3テーブルのアプローチは問題ありません。

2番目の質問では、foreignIdとassetIdの両方に外部キーを設定するだけです。ヌル値は外部キーでは問題ありません。

しかし、テーブルレベルの制約では、両方がnullになることも、両方にNULLを設定することもできません。

最後に、スキーマと制約の問題を解決したので、わかりやすく簡単なクエリを実行できます。そのアイデアは、あるタスクが資産を介してフロアに参加し、他のタスクがフロアにまっすぐに参加するというものです。そのためには、2つのクエリを結合する必要があります。

-- First query is the three level 
select task.* 
    from task 
    join asset on task.assetid = asset.id 
    join area on asset.areaid = area.id 
    join floor on area.floorid = floor.id 
where floor = xxxx 
UNION ALL 
-- Second query is the two level 
select task.* 
    from task 
    join area on task.areaid = area.id 
    join floor on area.floorid = floor.id 
where floor = xxxx 

これは正しい結果を返しますが、最速ではありません。各サブクエリにWHERE句を指定してNULL/NOT NULLを除外すると、それを高速化して調査する必要があります。