Как очистить все системные версионные таблицы одним запросом?

У меня есть запрос, который позволяет мне удалить все строки и сбросить все столбцы идентичности всех моих таблиц, не нарушая ссылок на внешние ключи. Этот запрос отлично работает для обычных таблиц SQL Server:

EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL';
EXEC sp_MSForEachTable 'DELETE FROM ?';
EXEC sp_MSForEachTable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL';
EXEC sp_MSforeachtable @command1 = 'DBCC CHECKIDENT (''?'', RESEED, 0)';

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

Я пытался использовать что-то вроде этого:

EXEC sp_MSForEachTable 'ALTER TABLE ? SET (SYSTEM_VERSIONING = OFF)';

EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL';
EXEC sp_MSForEachTable 'DELETE FROM ?';
EXEC sp_MSForEachTable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL';
EXEC sp_MSforeachtable @command1 = 'DBCC CHECKIDENT (''?'', RESEED, 0)';

EXEC sp_MSforeachtable 'ALTER TABLE ? SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = ''?''_history))';

но выдает ошибку:

SYSTEM_VERSIONING is not turned ON for table 'FOO.dbo.tbl_Foo_history'.

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

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

Я не уверен, что есть способ обойти это с помощью MSForeachTable, но вы можете почерпнуть некоторые идеи из статья здесь Аарона Бертрана.

Zohar Peled 20.06.2019 12:43

Запросы, которые вы пытаетесь выполнить, не могут выполняться в таблице каждый, только в таблицах с системной версией. Это ничем не отличается от попытки выполнить ALTER TABLE ? DROP Column SomeNonExistentColumn'. Вы не можете использовать sp_MSforeachtable для этого, вам придется написать скрипт, который работает только на нужных вам столах.

Panagiotis Kanavos 20.06.2019 12:57

Кстати, вы можете использовать TRUNCATE TABLE, чтобы удалить все, что а также переустанавливает IDENTITY. Текущее значение IDENTITY является частью данных таблицы, а не ее схемы.

Panagiotis Kanavos 20.06.2019 13:00

@PanagiotisKanavos Да, `sp_MSForEachTable был просто отправной точкой, так как раньше это работало для меня. Я просто понятия не имею, как написать сценарий для этого...

ruohola 20.06.2019 13:00

@PanagiotisKanavos Я не могу использовать TRUNCATE, так как выдает ошибку: Cannot truncate table 'dbo.tbl_Foo' because it is being referenced by a FOREIGN KEY constraint.

ruohola 20.06.2019 13:02
sys.tables имеет столбец temporal_type, который сообщает вам, является ли таблица временной таблицей/таблицей истории (и history_table_id указывает на таблицу истории). Вы можете проверить это заранее и сохранить результаты, хотя вам, возможно, все равно придется отказаться от sp_msforeachtable и написать свой собственный цикл курсора, в зависимости от. Кроме того, хорошенько подумайте о том, что означает для ваших темпоральных таблиц сброс их содержимого таким образом! В частности, убедитесь, что любые временные запросы не путаются при переписывании подобных вещей.
Jeroen Mostert 20.06.2019 13:03

@JeroenMostert Этот запрос будет использоваться только на этапе разработки, когда я пишу парсер, который заполняет базу данных данными. Я не хочу хранить там все неверные тестовые данные после каждого запуска программы.

ruohola 20.06.2019 13:04

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

Jeroen Mostert 20.06.2019 13:06

@JeroenMostert Да, это правда, это может быть одним из решений. Я просто ищу более элегантный, который может сохранить схему базы данных, как она будет на финальном этапе. Таким образом, я могу экспериментировать с запросами темпоральной таблицы, продолжая заполнять данные.

ruohola 20.06.2019 13:07

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

Jeroen Mostert 20.06.2019 13:10
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
10
2 655
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

ALTER TABLE dbo.tbl_Foo1 SET (SYSTEM_VERSIONING = OFF);
ALTER TABLE dbo.tbl_Foo2 SET (SYSTEM_VERSIONING = OFF);
ALTER TABLE ...

ALTER TABLE dbo.tbl_Foo1 NOCHECK CONSTRAINT ALL;
ALTER TABLE dbo.tbl_Foo2 NOCHECK CONSTRAINT ALL;
ALTER TABLE ...

DELETE FROM dbo.tbl_Foo1;
DELETE FROM dbo.tbl_Foo2;
DELETE FROM ...

DELETE FROM dbo.tbl_Foo1_history;
DELETE FROM dbo.tbl_Foo2_history;
DELETE FROM ...

DBCC CHECKIDENT ('[tbl_Foo1]', RESEED, 0);
DBCC CHECKIDENT ('[tbl_Foo2]', RESEED, 0);
DBCC CHECKIDENT ...

DBCC CHECKIDENT ('[tbl_Foo1_history]', RESEED, 0);
DBCC CHECKIDENT ('[tbl_Foo2_history]', RESEED, 0);
DBCC CHECKIDENT ...

ALTER TABLE dbo.tbl_Foo1 WITH CHECK CHECK CONSTRAINT ALL;
ALTER TABLE dbo.tbl_Foo2 WITH CHECK CHECK CONSTRAINT ALL;
ALTER TABLE ...

ALTER TABLE dbo.tbl_Foo1 SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.tbl_Foo1_history));
ALTER TABLE dbo.tbl_Foo2 SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.tbl_Foo2_history));
ALTER TABLE ...

Другие вопросы по теме