SQL: дополнительные внешние ключи - PullRequest
0 голосов
/ 22 января 2011

У меня есть следующие таблицы ....

«Этаж» (у которого много) «Район» (у которого много) «Актив»,

тогда у меня есть таблица "Task".

«Задача» может быть назначена либо «Области», либо «Активу»; поэтому у меня есть два столбца в таблице «Task» с именами areaId и assetId, один из которых должен иметь значение.

1-й вопрос: Как я могу запросить все задачи, которые произошли на данном этаже?

2-й вопрос: Как мне обеспечить ссылочную целостность?

3-ий вопрос: этот подход рекомендуется? Любые предложения приветствуются, если нет.

Большое спасибо за любые ответы,

ETFairfax

Ответы [ 2 ]

2 голосов
/ 22 января 2011

1-й вопрос:

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

должно дать вам форму запроса, который вы пытаетесь построить. (Конечно, вам на самом деле не нужно запрашивать таблицу Floor, если у вас уже есть FloorID)

2-й вопрос:

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

Или, в качестве альтернативы, вы можете сделать AreaID не равным NULL, добавить уникальное ограничение для таблицы активов (AreaID, AssetID), а затем сделать внешний ключ для таблицы активов ссылкой на оба столбца - это гарантирует, что если AssetID предоставляется, это ссылка на актив, который принадлежит правильному AreaID. Это также упростит ответ на вопрос Q1, если в Task

всегда есть AreaID

3-ий вопрос:

Трудно сказать, не зная, как все это будет использоваться. Я не думаю, что это un -разумный подход.

0 голосов
/ 22 января 2011

Давайте начнем с вопроса 3, это правильный подход? Это если он моделирует реальность. Если этажи, площади и объекты не похожи друг на друга, имеют более отличные свойства, чем общие свойства, и если операции над ними имеют тенденцию к различию, то подход с использованием трех таблиц вполне подходит.

Что касается второго вопроса, просто поместите внешние ключи как в areaId, так и в assetId. Нулевые значения в порядке во внешних ключах.

Но вам нужно ограничение на уровне таблицы, которое не позволит им обоим быть нулевыми и не позволит заполнить оба из них.

Наконец, решив проблему со схемой и ограничениями, мы можем выполнить запрос, что довольно просто. Идея состоит в том, что некоторые задачи соединяются через актив через область к полу, в то время как другие объединяются через область прямо к полу. Для этого вам нужно объединить два запроса:

-- 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 может ускорить его, что вам придется исследовать.

...