MS SQL Master + минимум один details
От: Flem1234  
Дата: 26.06.13 08:00
Оценка:
Добрый день.

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

Спасибо.
Re: MS SQL Master + минимум один details
От: Olaf Россия  
Дата: 26.06.13 08:57
Оценка: 1 (1)
Здравствуйте, Flem1234, Вы писали:

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

F>Как это реализовать?

Вставка данных в master /details всегда выполняется в одной транзакции — это будет гарантировать наличие как минимум одной записи в таблице details. Дополнительно, на таблице details создается триггер на обновление и удаление, в задачи которого входит проверка существования как минимум одной записи после выполнения модификаций в таблице.
Re[2]: MS SQL Master + минимум один details
От: hrensgory Россия  
Дата: 26.06.13 09:10
Оценка: +1
On 26.06.2013 12:57, Olaf wrote:

> F>Есть требование, что для одной мастер записи должна быть как минимум

> одна деталь.
> F>Как это реализовать?
>
> Вставка данных в master /details всегда выполняется в одной транзакции —
> это будет гарантировать наличие как минимум одной записи в таблице
> details.

Это почему? А если приложение ничего в detail вставлять не собирается?

--
WBR,
Serge.
Posted via RSDN NNTP Server 2.1 beta
Re[3]: MS SQL Master + минимум один details
От: _ABC_  
Дата: 26.06.13 09:17
Оценка: +1
Здравствуйте, hrensgory, Вы писали:

H>Это почему? А если приложение ничего в detail вставлять не собирается?


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

Re[3]: MS SQL Master + минимум один details
От: Olaf Россия  
Дата: 26.06.13 09:47
Оценка:
Здравствуйте, hrensgory, Вы писали:

>> Вставка данных в master /details всегда выполняется в одной транзакции —

>> это будет гарантировать наличие как минимум одной записи в таблице
>> details.

H>Это почему? А если приложение ничего в detail вставлять не собирается?


Если записи в master и details вставлять по отдельности, например с интервалом времени t (минута, час, день…), то в течение этого интервала будет 0 записей в таблице details – это нормально, но у автора требование наличие как минимум одной записи в details. Транзакция будет гарантировать, что если вставилась запись в master, значит существует как минимум одна связанная запись в details.
Re[4]: MS SQL Master + минимум один details
От: hrensgory Россия  
Дата: 26.06.13 11:17
Оценка:
On 26.06.2013 13:47, Olaf wrote:

>>> Вставка данных в master /details всегда выполняется в одной транзакции —

>>> это будет гарантировать наличие как минимум одной записи в таблице
>>> details.
>
> H>Это почему? А если приложение ничего в detail вставлять не собирается?
>
> Если записи в master и details вставлять по отдельности, например с
> интервалом времени t (минута, час, день…), то в течение этого интервала
> будет 0 записей в таблице details – это нормально, но у автора
> требование наличие как минимум одной записи в details. Транзакция будет
> гарантировать, что если вставилась запись в master, значит существует
> как минимум одна связанная запись в details.

Насколько я понял — речь идёт о том, чтобы обеспечить выполнение условия
"на каждый master — как минимум один detail" средствами БД.

При этом неясно как "транзакция будет гарантировать, что если вставилась
запись в master, значит существует как минимум одна связанная запись в
details" если приложение запишет данные только в master и не будет
вообще ничего писать в detail. В этом случае видимо должен сработать
триггер, но на какой таблице — непонятно (предполагая, что есть FK
master — detail и вставить в detail что-то заранее, не вставив в master
— нельзя).

--
WBR,
Serge.
Posted via RSDN NNTP Server 2.1 beta
Re[5]: MS SQL Master + минимум один details
От: Olaf Россия  
Дата: 26.06.13 11:45
Оценка:
Здравствуйте, hrensgory, Вы писали:

H>При этом неясно как "транзакция будет гарантировать, что если вставилась

H>запись в master, значит существует как минимум одна связанная запись в
H>details" если приложение запишет данные только в master и не будет
H>вообще ничего писать в detail. В этом случае видимо должен сработать
H>триггер, но на какой таблице — непонятно (предполагая, что есть FK
H>master — detail и вставить в detail что-то заранее, не вставив в master
H>- нельзя).

H>--

H>WBR,
H>Serge.

Здесь важна реализация, при которой первый detail всегда вставляется вместе с master записью и только так, сама транзакция, внутри которой идет только вставка в master конечно никак не поможет решить задачу.
Re[6]: MS SQL Master + минимум один details
От: Flem1234  
Дата: 26.06.13 13:17
Оценка:
Здравствуйте, Olaf, Вы писали:

O>Здесь важна реализация, при которой первый detail всегда вставляется вместе с master записью и только так, сама транзакция, внутри которой идет только вставка в master конечно никак не поможет решить задачу.


Если клиент попробует записать только мастер без детайлса, то тогда у меня требование будет нарушено.
Можно, конечно, создать хранимку, но хочется решения без нее, т.к. sql у меня генерируется из описания и придется дорабатывать генератор.
Re[2]: MS SQL Master + минимум один details
От: maxkar  
Дата: 26.06.13 13:27
Оценка:
Здравствуйте, Olaf, Вы писали:

O>Здравствуйте, Flem1234, Вы писали:


F>>Как это реализовать?

O>Вставка данных в master /details всегда выполняется в одной транзакции — это будет гарантировать наличие как минимум одной записи в таблице details.
Это как минимум потребует контроля над вставляющим кодом. И дополнительных проверках вручную при необходимости. Например, вставка производится пачками из временных таблиц и консистентность нужно проверить вручную (данные строятся другими выборками). Так можно и все остальные операции вручную проверять при желании.

O>Дополнительно, на таблице details создается триггер на обновление и удаление, в задачи которого входит проверка существования как минимум одной записи после выполнения модификаций в таблице.

И это далеко не во всех сценариях работает. Например, в одной транзакции удалить все detail и потом вставить новые. Триггер не даст.

Хотя, конечно, все зависит от требований ТС.
Re[3]: MS SQL Master + минимум один details
От: Flem1234  
Дата: 26.06.13 13:46
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Хотя, конечно, все зависит от требований ТС.


Требования у ТС простые:
1. С точки зрения бизнеса, у мастера должна быть как минимум одна деталь, иначе ситуация не имеет смысла.
2. У меня есть генератор ескьюэля, которые генерирует запросы к базе, вставляя сначала мастеров, а потом их детали (как они и приходят из внешней системы) и удаляя в обратном порядке.
3. Надо не допустить сохранения некорректных данных с точки зрения бизнеса (1) как можно меньшими усилиями.
Re[4]: MS SQL Master + минимум один details
От: wildwind Россия  
Дата: 28.06.13 17:59
Оценка:
Здравствуйте, Flem1234, Вы писали:

F>Требования у ТС простые:

F>1. С точки зрения бизнеса, у мастера должна быть как минимум одна деталь, иначе ситуация не имеет смысла.

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

F>2. У меня есть генератор ескьюэля, которые генерирует запросы к базе, вставляя сначала мастеров, а потом их детали (как они и приходят из внешней системы) и удаляя в обратном порядке.


Он делает это в одной транзакции? Если нет, его придется переписывать, без вариантов.

F>3. Надо не допустить сохранения некорректных данных с точки зрения бизнеса (1) как можно меньшими усилиями.


Есть несколько подходов.
1. Не давать приложению права на прямой insert, а дать некий API, который будет контролировать это требование.

2. Изобрести "триггер на commit", где и проверять выполнение условия. Такого триггера в SQL конечно нет. Но, к примеру, в Oracle возможен известный трюк с материализованным представлением. Может и в MSSQL можено придумать что-то подобное.

3. Попытаться реализовать чисто декларативными ограничениями. Например добавить в мастер таблицу внешний ключ со ссылкой на детальную. С отложенной проверкой, разумеется.
Re: MS SQL Master + минимум один details
От: maloi_alex СССР  
Дата: 28.06.13 18:36
Оценка:
Здравствуйте, Flem1234, Вы писали:

F>Добрый день.


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

F>Как это реализовать?

Какое-то долбанутое требование, которое маловероятно соответствует действительности. Хотелось бы подробностей.

F>Спасибо.
Re[2]: MS SQL Master + минимум один details
От: Olaf Россия  
Дата: 29.06.13 14:18
Оценка:
Здравствуйте, maloi_alex, Вы писали:

_>Какое-то долбанутое требование, которое маловероятно соответствует действительности. Хотелось бы подробностей.


Автору топика предъявлено требование, реализовать разновидность связи один ко многим (one-to-many), где заранее известно минимальное кол-во записей со стороны многие (many), в частности 1 to 1-or-many (1 к 1 или более). Бывают и другие случаи, когда известно максимальное кол-во записей, например: летчик в месяц делает не больше 50-и вылетов, спортсмен может использовать не больше 5-и попыток, в человеческом организме не больше 500 костей и т.п.

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

Обычно возникает, где требуется хранить первоначальное значение одного из атрибутов master сущности, который изменяется во времени и требует протоколирование (ведение журнала), например вес, температура, географическое положение, статус/состояние, склад/магазин и т.п.

Проблема данной задачи заключается в том, что в ней необходимо выполнить требование наличия как минимум одной деталь записи при отсутствии таковой и с минимальными изменениями приложения. Но даже в такой постановке автором топика она решаема, просто нужно переделать вставку данных, т.к. примитивными настройками на уровне СУБД здесь не обойдешься (PK, FK, constraint и т.п.). Кроме тех вариантов, что предлагали выше можно:
  1. Создать дополнительную структуру в БД аналогичную master и все новые записи добавлять только в нее. После того как пришли детали, объединять их с мастер записями и вставлять в целевую master таблицу в одной транзакции.
  2. Если по бизнес-требованиям терпит отсутствие деталей для мастер записей в течение какого-то времени t (окно), тогда по приходу из внешнего источника загружать детали и чистить несвязанные мастер записи.
  3. ...
Re[5]: MS SQL Master + минимум один details
От: maxkar  
Дата: 29.06.13 16:40
Оценка: 5 (1)
Здравствуйте, wildwind, Вы писали:


Раз уж дискуссия ушла в более общее русло, добавлю.

W>2. Изобрести "триггер на commit", где и проверять выполнение условия. Такого триггера в SQL конечно нет. Но, к примеру, в Oracle возможен известный трюк с материализованным представлением. Может и в MSSQL можено придумать что-то подобное.


"Триггер на коммит" — это на любой коммит в базе, или выполнение триггера в момент коммита? Второй в некоторых базах есть. Например, код для решения исходной задачи на postres'е (9-ка):
  Скрытый текст
CREATE FUNCTION chk_master_detail() RETURNS TRIGGER AS $$
BEGIN
  PERFORM id FROM detail WHERE master_id = NEW.id;
  IF NOT FOUND THEN
    RAISE 'KEY VIOLATION!';
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE FUNCTION chk_detail_master() RETURNS TRIGGER AS $$
DECLARE
 FND boolean;
BEGIN
  PERFORM id FROM master WHERE id = OLD.master_id;
  IF NOT FOUND THEN
    RETURN NEW;
  END IF;
  FND := EXISTS(SELECT id FROM detail WHERE master_id = OLD.master_id);
  IF NOT FND THEN
    RAISE 'KEY VIOLATION!';
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;


CREATE TABLE master(
  id integer NOT NULL PRIMARY KEY
);

CREATE TABLE detail(
  id integer NOT NULL PRIMARY KEY,
  master_id integer NOT NULL REFERENCES master(id)
);

CREATE CONSTRAINT TRIGGER master_detail_has_one AFTER INSERT OR UPDATE
  ON master
  DEFERRABLE INITIALLY DEFERRED
  FOR EACH ROW
  EXECUTE PROCEDURE chk_master_detail();

CREATE CONSTRAINT TRIGGER master_detail_has_one_detail_t AFTER UPDATE OR DELETE
  ON detail
  DEFERRABLE INITIALLY DEFERRED
  FOR EACH ROW
  EXECUTE PROCEDURE chk_detail_master();

Туда еще триггер на транкейт detail добавить нужно.

Кстати, с использованием deferred trigger можно сделать и триггер на коммит (выполняется один раз в момент коммита).
  Скрытый текст
CREATE FUNCTION schedule_commit_check() RETURNS TRIGGER AS $$
BEGIN
  CREATE TEMP TABLE IF NOT EXISTS on_commit_check (
    v boolean primary key 
  ) ON COMMIT DROP;

  UPDATE on_commit_check SET v = TRUE;
  IF NOT FOUND THEN
    CREATE CONSTRAINT TRIGGER master_detail_has_one AFTER INSERT
      ON on_commit_check
      DEFERRABLE INITIALLY DEFERRED
      FOR EACH ROW
      EXECUTE PROCEDURE chk_global_master_detail();

    INSERT INTO on_commit_check VALUES (true);
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE FUNCTION chk_global_master_detail() RETURNS TRIGGER AS $$
DECLARE 
 fnd boolean;
BEGIN
  fnd := EXISTS(SELECT master.id 
    FROM master
    LEFT OUTER JOIN detail on master.id = detail.master_id
    WHERE detail.master_id IS NULL
  );
  IF FND     THEN
    RAISE 'M/1D RELATION VIOLATION!';
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;


CREATE TABLE master(
  id integer NOT NULL PRIMARY KEY
);

CREATE TABLE detail(
  id integer NOT NULL PRIMARY KEY,
  master_id integer NOT NULL REFERENCES master(id)
);

CREATE TRIGGER master_detail_has_one AFTER INSERT OR UPDATE
  ON master
  FOR EACH STATEMENT
  EXECUTE PROCEDURE schedule_commit_check();

CREATE TRIGGER master_detail_has_one_detail_t AFTER UPDATE OR DELETE
  ON detail
  FOR EACH STATEMENT
  EXECUTE PROCEDURE schedule_commit_check();

schedule_commit_check на таблицы навешивать триггерами на изменение системных таблиц/view.

Касательно MSSQL. Некоторые люди творят ужасы, чтобы проверить констрейны в момент коммита (как раз с использованием вычисляемых материализованных колонок в таблицах).

W>3. Попытаться реализовать чисто декларативными ограничениями. Например добавить в мастер таблицу внешний ключ со ссылкой на детальную. С отложенной проверкой, разумеется.

Вот с отложенной проверкой будут как раз основные проблемы. Не поддерживает их MSSQL ни в каком виде. А так был бы, наверное, самый простой и понятный вариант. Где-то считать количество detail для master и на это значение повесить check constraint. В идеале (если все поддерживается) это был бы materialized view (master.id, sum(detail.id)) и check constraint на вторую колонку.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.