Как реализовать ссылочную целостность в подтипах

у меня есть следующие таблицы в реляционной базе данных:

[Sensor]
LocationId [PK / FK -> Location]
SensorNo [PK]

[AnalogSensor]
LocationId [PK/FK -> Sensor]
SensorNo [PK/FK -> Sensor]
UpperLimit
LowerLimit

[SwitchSensor]
LocationId [PK/FK -> Sensor]
SensorNo [PK/FK -> Sensor]
OnTimeLimit

[Reading]
LocationId [PK/FK -> Sensor]
SensorNo [PK/FK -> Sensor]
ReadingDtm [PK]

[ReadingSwitch]
LocationId [PK/FK -> Reading]
SensorNo [PK/FK -> Reading]
ReadingDtm [PK/FK -> Reading]
Switch

[ReadingValue]
LocationId [PK/FK -> Reading]
SensorNo [PK/FK -> Reading]
ReadingDtm [PK/FK -> Reading]
Value

[Alert]
LocationId [PK/FK -> Reading]
SensorNo [PK/FK -> Reading]
ReadingDtm [PK/FK -> Reading]

В основном, ReadingSwitch и ReadingValue являются подтипами чтения и SwitchSensor и AnalogSensor являются подтипами датчика. Чтение может быть SwitchReading или значение ValueReading - он не может быть одновременно, и датчик может быть либо AnalogSensor или SwitchSensor.

только я столкнулся с этой до сих пор здесь.

там, конечно, должно быть лучше способ делать такие вещи.

единственный другой способ, который я могу придумать, - это не иметь подтипов, но полностью расширить все:

[SwitchSensor]
LocationId [PK/FK -> Location]
SensorNo [PK]

[AnalogSensor]
LocationId [PK/FK -> Location]
SensorNo [PK]

[SwitchReading]
LocationId [PK/FK -> SwitchSensor]
SensorNo [PK/FK -> SwitchSensor]
ReadingDtm
Switch

[AnalogReading]
LocationId [PK/FK -> AnalogSensor]
SensorNo [PK/FK -> AnalogSensor]
ReadingDtm
Value

[AnalogReadingAlert]
LocationId [PK/FK -> AnalogReading]
SensorNo [PK/FK -> AnalogReading]
ReadingDtm [PK/FK -> AnalogReading]

[SwitchReadingAlert]
LocationId [PK/FK -> SwitchReading]
SensorNo [PK/FK -> SwitchReading]
ReadingDtm [PK/FK -> SwitchReading]

что может быть не так уж плохо, но у меня также есть таблицы, которые ссылаются на таблицу оповещений, поэтому их тоже придется дублировать:

[AnalogReadingAlertAcknowledgement]
...
[AnalogReadingAlertAction]
...
[SwitchReadingAlartAcknowledgement]
...
[SwitchReadingAlartAction]

etc.

имеет ли эта проблема какой-либо смысл для кого-либо??

2 ответов


ничего из этого не нужно, особенно удвоение таблицы. Это чистое безумие.

введение

поскольку стандарт для моделирования реляционных баз данных (IDEF1X) широко используется уже более 25 лет (по крайней мере, в высококачественной, высокопроизводительной части рынка), я использую эту терминологию. Date & Darwen,несмотря на1 в соответствии с большой работой, которую они сделали, чтобы прогрессаподавления Модель Отношения, они не знали IDEF1X, пока я не довел его до их сведения в 2009 году, и, таким образом, имеет новую терминологию2 для стандартной терминологии, которую мы использовали в течение десятилетий. Кроме того, новая терминология не касается всех случаев, как это делает IDEF1X. Поэтому я использую стандартные термины и избежать новой терминологии.

  • даже понятие "распределенный ключ " не распознает базовые обычные отношения PK::FK, их реализацию в SQL и их силу.

  • реляционной, и поэтому IDEF1X, понятие коды и их миграции.

  • конечно, поставщики не совсем на мяче, и у них есть странные вещи, такие "частичные индексы" и т. д., которые совершенно не нужны, когда основы поняты. Но известные "академики" и " теоретики" придумывая неполные новые концепции, когда концепция была стандартизирована и дала полное лечение 25 лет назад ... это неожиданно и неприемлемо.

предостережение

IEC/ISO/ANSI SQL едва обрабатывает 3nf Codd (Date & Darwen's "5NF") адекватно, и он вообще не поддерживает структуры Basetype-Subtype; для этого нет декларативных ограничений (и должно быть).

  • поэтому, для того, чтобы обеспечить полный набор Правила, выраженные в модели данных, как Basetype:: Subtype, так и Subtype:: Basetype, мы должны немного поиграть с CHECK CONSTRAINTs и т. д. (Я избегаю использования триггеров по ряду причин).

рельеф

тем не менее, я принимаю все это во внимание. Для того, чтобы я эффективно предоставлял услугу моделирования данных на StackOverflow, без необходимости предварять это полным дискурсом, я намеренно предоставляю модели, которые могут быть реализованы способными людьми, используя существующие SQL и существующие ограничения, в какой бы степени они ни требовались. Он уже упрощен и содержит общий уровень правоприменения. Если есть какие-либо вопросы, просто спросите, и вы получите.

мы можем использовать как пример графики в документе по ссылке и полностью IDEF1X-уступчивый Модель Данных Датчика

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

реализация ссылочной целостности Для Basetype-Subtype

существует два типа структур Basetype-Subtype.

Эксклюзивный Подтипа

Exclusive означает, что для каждого подтипа должна быть одна и только одна строка Строку базового типа. В терминах IDEF1X в базовом типе должен быть столбец дискриминатора, который идентифицирует строку подтипа, которая существует для него.

  • для более чем двух подтипов это требуется, и я реализую столбец дискриминатора.

  • для двух подтипов, так как это легко получить из существующих данных (например. Sensor.IsSwitch является дискриминатором для Reading), Я не моделирую дополнительный явный столбец дискриминатора для Reading. Тем не менее, вы можете следовать стандарту до буквы и реализовать дискриминатор.

я подробно рассмотрю каждый аспект.

  1. столбец дискриминатора нуждается в CHECK CONSTRAINT чтобы убедиться, что он находится в пределах диапазона значений, например: IN ("B", "C", "D"). IsSwitch это BIT, что равно 0 или 1, так что это уже ограничено.

  2. поскольку PK базового типа определяет его уникальность, только одна строка базового типа будет разрешено; вторая строка базового типа (и, следовательно, вторая строка подтипа) не может быть вставлена.

    • поэтому излишне, полностью избыточно, дополнительный ненужный индекс, реализовать индекс, такой как (PK, дискриминатор) в базовом типе, как советует ваша ссылка. Уникальность заключается в ПК, и поэтому ПК плюс что-либо будет уникальным).

    • IDEF1X не требует дискриминатора в таблицах подтипов. В подтипе, который опять же ограничивается уникальностью его PK, согласно модели, если дискриминатор был реализован как столбец в этой таблице, каждая строка в нем будет иметь одинаковое значение для дискриминатора (каждая книга будет "B"; каждый ReadingSwitch будет IsSwitch). Поэтому абсурдно реализовывать дискриминатор в виде столбца в подтипе. И опять же, совершенно избыточный, дополнительный ненужный индекс, для реализации такого индекса, как (PK, Discriminator) в подтипе: уникальность заключается в ПК, а значит ПК плюс что угодно будет уникальным).

    • метод, указанный в ссылке, является неуклюжим и раздутым (массовое дублирование данных без цели) способом реализации ссылочной целостности. Вероятно, есть веская причина, по которой автор не видел эту конструкцию нигде больше. Это основная неспособность понять SQL и использовать его как это эффективно. Эти " решения "типичны для людей, которые следуют догме" SQL не может сделать..." и поэтому слепы к тому, что может сделать SQL. Ужасы, порождаемые слепыми "методами" Фаулера и Эмблера, еще хуже.

  3. подтип PK также является FK для базового типа, то есть все, что требуется, чтобы убедиться, что подтип не существует без родительского базового типа.

      для любого ПК, в зависимости от базового типа-подтипа вставляется первая будет успешно; и в зависимости от базового типа-подтипа пытался после этого, потерпеть неудачу. Поэтому в таблице подтипов беспокоиться не о чем (вторая строка базового типа или вторая строка подтипа для того же ПК запрещена).
      .
  4. в SQL CHECK CONSTRAINT ограничивается проверкой вставить строку. Нам нужно проверить вставленную строку против других строк, либо в той же таблице или в другой таблице. Поэтому "пользовательская" функция требуемый.

    • напишите простой UDF, который будет проверять наличие PK и дискриминатор в базовом типе и возвращает 1, Если EXITS или 0, если NOT EXITS. Вам понадобится один UDF на базовый тип (а не на подтип).

    • в подтипе реализуйте a CHECK CONSTRAINT который вызывает UDF, используя PK (который является как базовым, так и подтипом) и дискриминатор стоимостью.

    • я реализовал это в десятках больших, реальных баз данных, на разных платформах SQL. Вот "определяемый пользователем"Функции Код и DDL код для объектов, на которых оно основывается.

    • этот конкретный синтаксис и код протестирован на Sybase ASE 15.0.2 (они очень консервативны в отношении стандартов SQL соответствие.)

    • я знаю, что ограничения на "определенные пользователем" функции различны для каждой платформы SQL. Однако это самый простой из простых, и AFAIK каждая платформа позволяет эту конструкцию. (Не знаю, что делают не-SQLs.)

    • да, конечно, эта умная маленькая техника может быть использована для реализации любого нетривиального правила данных, которое вы можете нарисовать в модели данных. В частности, для преодоления ограничений SQL. Заметьте мой осторожно, чтобы избежать двухсторонних ограничений (круговые ссылки).

  5. на CHECK CONSTRAINT в подтипе гарантирует, что PK плюс правильно дискриминатор существует в Basetype. Что означает, что только этот подтип существует для базового типа (ПК).
    • любая последующая попытка вставить другое подтип (т. е. нарушить исключительное правило) не удастся, потому что PK + дискриминатор не существует в базовом типе.

    • любая последующая попытка вставить другую строку того же подтипа предотвращается уникальностью его ограничения PK.

  6. единственный бит, который отсутствует (не упоминается в ссылке), - Это правило "каждый базовый тип должен иметь хотя бы один подтип", не применяется. Это легко покрывается транзакционным кодом (I do не посоветуйте ограничения, идущие в два направления или триггеры); используйте правильный инструмент для задания.

неисключительный подтип

базовый тип (Родительский) может содержать более одного подтипа (дочернего)

  1. не существует ни одного подтипа для идентификации.

    • дискриминатор не применяется к неисключительным подтипам.

    • существование подтипа определяется путем выполнения проверки существования на Таблица подтипов, используя базовый тип PK.

  2. просто исключить CHECK CONSTRAINT Это вызывает UDF выше.

    • на PRIMARY KEY, FOREIGN KEY, и обычный диапазон CHECK CONSTRAINTs, адекватно поддерживают все требования для неисключительных подтипов.

ссылка

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

Примечание

  1. Реляционная Модель. После многих лет взаимодействия, основанного на горе последовательных доказательств, я пришел к выводу, что их работа на самом деле является ее унижением. Они ничего не сделали для дальнейшей плодотворной работы доктора Кодда, Реляционная Модель и все, чтобы повредить и подавить его.
  2. у них есть частные определения для реляционных терминов, что, конечно, серьезно препятствует любому общению. У них есть новая терминология для терминов, которые у нас были с 1970 года, чтобы казаться, что они "изобрели" его. Типично для мошенников и воров.

ответ на комментарий

этот раздел может быть пропущен всеми читателями, которые сделали не комментировать.

Сэм: Я заметил, что этот подход не мешает кому-то использовать UPDATE для изменения значения дискриминатора базового типа. Как это можно предотвратить? The FOREIGN KEY + дубликат столбца дискриминатора в подходе к подтипам, похоже, преодолевает это.

да. Этот метод не мешает кому-то использовать UPDATE Изменить ключ или столбец в какой-либо несвязанной таблице или головные боли. Он отвечает на конкретный вопрос, и ничего другого. Если вы хотите предотвратить определенные команды DML или что-то еще, используйте средство SQL, предназначенное для этого цель. Все это выходит за рамки данного вопроса. В противном случае каждый ответ должен касаться каждого несвязанного вопроса.

ответ. Так как мы должны использовать Открытые Стандарты Архитектуры, доступный с 1993 года, все изменения в БД происходят только через транзакции ACID. Это означает прямой INSERT/UPDATE/DELETE, для всех таблиц запрещено; данные сохраняют целостность и согласованность (кислотная терминология). В противном случае, конечно, у вас есть кровоточащий беспорядок, такой как ваш например. и последствия. Эти уроды не понимают транзакций, они понимают только один файл INSERT/UPDATE/DELETE. Опять же, вне поля зрения. Если вам нужно больше деталей, пожалуйста, откройте новый вопрос, и я отвечу на него подробно.

далее, FK + Duplicate D + Duplicate Index (и огромная стоимость в нем !) ничего подобного, я не знаю, откуда у вас" кажется".

dtheodor: Этот вопрос касается ссылочной целостности. Ссылочная целостность не означает "проверить, что ссылка действительна при вставке и забыть об этом". Это означает "поддерживать действительность ссылки навсегда". Метод duplicate discriminator + FK гарантирует эту целостность, ваш подход UDF-нет. Это несомненно, что UPDATEs не должен нарушать ссылку.

проблема здесь двоякая. Во-первых, вам нужно базовое образование в другие районы re реляционные базы данных и открытые стандарты архитектуры. Во-вторых, вы нуждаетесь в депрограммировании, потому что, хотя я и дал вам ответ, вы не понимаете его, вы рабски повторяете культовую мантру, что этот конкретный метод не делает того, что делает массово неэффективный культовый метод. Не повторяя мою просьбу открыть новый вопрос и, таким образом, дать полный ответ на ту другую область реляционных баз данных, которую вы, очевидно, не понимаете (никто в культе Date & Darwen не понимает основ реляционных баз данных), я правда не знаю, что делать.

хорошо, короткий ответ, который действительно относится к другому вопросу как дискриминатор в исключительных подтипах защищен от недопустимого обновления ?

  1. ясность. Да,ссылочная целостность не означает "проверьте, что ссылка действительна при вставке и забудьте об этом". Я не сказал, что это значит.

    • ссылочная целостность означает Ссылки в базе данных FOREIGN KEY целостность с PRIMARY KEY, на которые он ссылается.

    • декларативная ссылочная целостность означает объявил ссылки в базе данных ... CONSTRAINTВНЕШНИЙ КЛЮЧ... REFERENCES ...
      CONSTRAINT CHECK ...
      поддерживаются платформой РСУБД, а не кодом приложения.

    • это не mean " поддерживать действительность ссылки навсегда" любой.

  2. исходный вопрос касается RI для подтипов, и я ответил на него, предоставив DRI.

    • необходимо подчеркнуть, что массово неэффективные структуры и дублированные таблицы, как "учили" ваши культовые лидеры, не требуются.
  3. ваш вопрос не касается RI или DRI.

  4. Ваш вопрос, хотя и задан неправильно, потому что вы ожидаете, что метод предоставит то, что метод не предоставляет, и вы не понимаете, что ваше требование выполняется другими средствами, это как дискриминатор в исключительных подтипах защищен от недопустимого обновления ?

  5. ответ: используйте стандарты открытой архитектуры, которые мы должны использовать с 1993 года. Что мешает все недействительным UPDATEs. Если вы потрудились прочитать связанные документы и понять они, ваша забота-это не проблема, ее не существует. Это короткий ответ.

    • никто не может подойти к базе данных и изменить столбец здесь или значение там. Использование SQL напрямую или приложения, которое использует SQL напрямую. Если чтобы разрешили, у вас не будет защищенной базы данных, у вас будет проститутка в дешевом борделе.

    • все обновления (нижний регистр) в базе данных (включая многорядные INSERT/UPDATE/DELETE) реализованы как транзакции ACID SQL. И ничего, кроме сделки. The set сделок составляют API базы данных, который предоставляется любому приложению, использующему базу данных.

    • SQL имеет транзакции ACID. Не-SQLs не имеют транзакций. Ваш культ любит не-SQLs. Они абсолютно ничего не знают о транзакциях, пусть откроют архитектуру. Их не-архитектура монолитный стог. И "база данных", которая обновляется каждый месяц.

    • поскольку только транзакции, которые вы пишете, будут вставлять basetype+subtype в одну транзакцию в качестве одной логической единицы работы, целостность (целостность данных, а не ссылочная целостность) basetype:: subtype связь поддерживается и поддерживается в рамках базы данных. Поэтому все обновления базы данных будут действительны, никаких недопустимых обновлений не будет.

    • так как вы не настолько глупы, чтобы написать код, который UPDATEs столбец дискриминатора в одной строке без сопровождающего DELETE Previous_Subtype, поместите его в транзакцию и GRANT EXEC разрешение для него пользователю ROLES, не будет недопустимого дискриминатора нигде в база данных.


второй вариант также чреват проблемами-например, для датчиков (и предполагая, что SensorNo является суррогатным ключом), потому что у вас нет базовой таблицы, суррогат SensorNo либо не уникален между таблицами подклассов, если вы не используете механизм klugey для выдачи ключей во всех таблицах подклассов (или используете guid).

Это было бы усилено, если бы у вас был пользовательский интерфейс, который "объединяет" различные типы датчиков, например, список, показывающий объединение аналогового и коммутатора аппаратура наблюдения.

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

например, создайте процедуры вставки для различных Поднаборов, которые вставляют соответствующие записи базы и подкласса в единицу работы. Вы можете пойти дальше, а затем отменить привилегии вставки на любой из таблиц, тем самым заставляя вставку через SPROC.

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