Сопоставление SQL между несколькими таблицами - PullRequest
6 голосов
/ 11 января 2010

Это вопрос разработки SQL. Сначала настройка. У меня есть три таблицы:

  1. A, который автоматически заполняется на основе запроса к связанному серверу. Данные в этой таблице не могут быть изменены;
  2. B, в котором всего около десятка строк, содержащих имена для коллекций As;
  3. AtoB - таблица сопоставления, по которой As организованы в именованные коллекции с внешними ключами в обоих столбцах;

SQL Mapping Table

Например, A содержит:

  1. Жираф
  2. Owl
  3. Tiger

А В содержит:

  1. Сиэтлский зоопарк
  2. Зоопарк Сан-Хосе

А AtoB содержит:

1,1 (Жираф в Сиэтле)
2,1 (Сова в Сиэтле)
3,1 (Тигр в Сиэтле)
2,2 (Сова в Сан-Хосе)

Теперь проблема:

Меня попросили включить в некоторые из этих коллекций элементы, которых нет в A. Итак, я создаю таблицу C с такими же столбцами идентификаторов и имен, что и в A, и заполняю ее. В соответствии с более ранним примером, скажем, C содержит:

  1. Dragon

Вопрос в том, как включить элементы из C в AtoB? Что если мне нужно будет включить дракона в зоопарк Сиэтла?

Мой первый инстинкт, будучи наивным, состоял в том, чтобы создать представление V, содержащее объединение A и C, и изменить AtoB на VtoB. Вот где моя наивность окупилась: нельзя создать внешний ключ для представления.

Я подозреваю, что есть стандартные, правильные способы связать один или несколько A или C с B.

Ответы [ 4 ]

10 голосов
/ 12 января 2010

Чтобы расширить решение Артура Томаса, приведем union без ГДЕ в подотборах, чтобы вы могли создать универсальное представление:

SELECT A.Name as Animal, B.Name as Zoo FROM A, AtoB, B
    WHERE AtoB.A_ID = A.ID && B.ID = AtoB.B_ID 
UNION
SELECT C.Name as Animal, B.Name as Zoo FROM C, CtoB, B
    WHERE CtoB.C_ID = C.ID && B.ID = CtoB.B_ID

Затем вы можете выполнить запрос как:

SELECT Animal FROM zoo_animals WHERE Zoo="Seattle Zoo"
5 голосов
/ 12 января 2010

Если вы не можете поместить Дракона в А, вам нужно будет создать еще одну таблицу и другую таблицу ссылок. Проблема заключается в создании уникального набора данных, который должен быть сохранен (другая таблица), который не может быть таким же, как А. ключи, которые гарантируют, что ссылка является ссылкой из набора A. Таким образом, вы можете создать такие таблицы:

imaginary_creatures

  • ID
  • имя

imaginary_creatures_to_b

  • imaginary_creatures_id (ссылка на таблицу imaary_creatures)
  • b_id (ссылка на таблицу зоопарков)

Позже, когда вы хотите собрать всех существ в зоопарке, вы можете сделать СОЮЗ

SELECT A.Name FROM A where A.ID IN 
   (SELECT AB.A_ID FROM AtoB AB WHERE B_ID = 
      (SELECT B.ID FROM B WHERE B.Name = 'Zoo Name'))
UNION
SELECT i.name FROM imaginary_creatures i i.id IN 
   (SELECT ic.imaginary_creatures_id FROM imaginary_creatures_to_c ic 
    WHERE ic.b_id = (SELECT B.ID FROM B WHERE B.Name = 'Zoo Name'))

Возможно, есть лучший способ написать это, но он должен работать для ваших целей.

1 голос
/ 12 января 2010

У Артура Томаса есть хорошее решение, другое возможное решение - добавить столбец в таблицу ссылок, указывающий, к какой таблице (A или C) он относится. Затем установите отношения с помощью триггеров, а не внешних ключей. Но на самом деле решение Артура - предпочтительный способ сделать это.

0 голосов
/ 11 января 2010

То, что вы хотите сделать, это поместить Dragon в A, и если вы хотите выбрать ВСЕ записи из A независимо от того, имеют ли они соответствующую запись в AtoB, выполните LEFT OUTER JOIN. Примерно так:

SELECT * FROM A
LEFT OUTER JOIN AtoB
ON A.id = AtoB.A_ID

Редактировать: Это сработало бы, только если бы вы могли добавить свои новые записи в A. Я пропустил тот факт, что вы не можете. Я думаю, что решение Артура Томаса - то, что вы хотите.

...