Копировать в модели смежности

Мне нужно создать хранимую процедуру sql (Sql Server 2008 - T-SQL), которая копирует узел в модели смежности.

Таблицу можно рассматривать как имеющую два столбца: Id и ParentId (от FK до Id). Копирование означает, что также необходимо скопировать всех подчиненных.

Я думаю, что использование WITH — хорошее начало, но мне любопытно, смогу ли я сделать эту копию без использования курсоров.


person Lieven Cardoen    schedule 24.11.2010    source источник


Ответы (2)


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

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

РЕДАКТИРОВАТЬ: Как указано в 'a_horse_with_no_name', есть способ в общем SQL для обработки списков смежности, рекурсивных общих табличных выражений.

person Tony    schedule 24.11.2010
comment
Что ж, на самом деле я преобразовываю свою модель вложенного набора в список смежности, потому что у нас есть серьезные проблемы с производительностью при вставке узлов (для одной вставки в среднем необходимо выполнить 50 000 обновлений). - person Lieven Cardoen; 24.11.2010
comment
Я вижу вашу проблему с моделью вложенных наборов с таким количеством вставок! В этом случае может быть лучше прочитать список из базы данных и обработать его на каком-либо другом языке, чтобы сгенерировать необходимый SQL. - person Tony; 24.11.2010
comment
@Tony: существует общий способ извлечения поддерева в SQL, он называется рекурсивным общим табличным выражением. - person a_horse_with_no_name; 24.11.2010
comment
@a_horse_with_no_name: Вы правы, доступны рекурсивные CTE (+1 за указание на это). Я должен признать, что ответил на вопрос об общем SQL, а не о T-SQL (я понимаю, что вопрос помечен как SQL Server). Я только что выполнил поиск рекурсивного CTE, и на странице MS есть пример со списком смежности: msdn.microsoft.com/en-us/library/ms186243.aspx - person Tony; 24.11.2010
comment
@Tony: Я хотел отметить, что рекурсивный CTE является общим SQL. Это не относится к SQL Server. Его поддерживают все основные СУБД (кроме MySQL). - person a_horse_with_no_name; 24.11.2010
comment
@a_horse_with_no_name, если быть точным, CTE появился в SQL-99, поэтому его поддерживает любая СУБД, совместимая с SQL-99 (например, sqlite очень распространен, что для меня означает основной механизм базы данных, но он не поддерживает его) - person Unreason; 25.11.2010

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

  • денормализация данных или
  • используя его как своего рода шаблон.

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

Итак, вы должны обновить ответ более полным примером того, что вы пытаетесь сделать.

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

So

  1. WITH INSERT во временную таблицу
  2. ОБНОВИТЕ идентификаторы
  3. ВСТАВИТЬ в исходную таблицу
  4. УДАЛИТЬ временные записи

Процедура должна быть такой, потому что было бы сложно изменить идентификаторы (как идентификаторы записи, так и идентификатор, относящийся к родителю) в начальном WITH INSERT. Однако это могло бы быть возможно, если бы была хорошая функция, которая зависела бы только от max_id или только от старых идентификаторов.

person Unreason    schedule 25.11.2010