Проблема с соглашениями об именах таблиц и управлением политиками в SQL Server 2016

10

В SQL Server 2012 у меня была политика, запрещающая использование пробелов в имени таблицы. Однако, когда я использую ту же политику в SQL Server 2016, я получаю сообщение об ошибке.

Вот код для условия:

DECLARE @condition_id INT
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'No Spaces', @description=N'No spaces in table names.', @facet=N'IMultipartNameFacet', @expression=N'<Operator>
  <TypeClass>Bool</TypeClass>
  <OpType>NOT_LIKE</OpType>
  <Count>2</Count>
  <Attribute>
    <TypeClass>String</TypeClass>
    <Name>Name</Name>
  </Attribute>
  <Constant>
    <TypeClass>String</TypeClass>
    <ObjType>System.String</ObjType>
    <Value>% %</Value>
  </Constant>
</Operator>', @is_name_condition=4, @obj_name=N'% %', @condition_id=@condition_id OUTPUT
SELECT @condition_id

Вот код для политики:

DECLARE @object_set_id INT
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'Table Names_ObjectSet', @facet=N'IMultipartNameFacet', @object_set_id=@object_set_id OUTPUT
SELECT @object_set_id

DECLARE @target_set_id INT
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/Sequence', @type=N'SEQUENCE', @enabled=False, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/Sequence', @level_name=N'Sequence', @condition_name=N'', @target_set_level_id=0

EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/StoredProcedure', @type=N'PROCEDURE', @enabled=False, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/StoredProcedure', @level_name=N'StoredProcedure', @condition_name=N'', @target_set_level_id=0

EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/Synonym', @type=N'SYNONYM', @enabled=False, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/Synonym', @level_name=N'Synonym', @condition_name=N'', @target_set_level_id=0

EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/Table', @type=N'TABLE', @enabled=True, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/Table', @level_name=N'Table', @condition_name=N'', @target_set_level_id=0

EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/UserDefinedFunction', @type=N'FUNCTION', @enabled=False, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/UserDefinedFunction', @level_name=N'UserDefinedFunction', @condition_name=N'', @target_set_level_id=0

EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/UserDefinedType', @type=N'TYPE', @enabled=False, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/UserDefinedType', @level_name=N'UserDefinedType', @condition_name=N'', @target_set_level_id=0

EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/View', @type=N'VIEW', @enabled=False, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/View', @level_name=N'View', @condition_name=N'', @target_set_level_id=0

EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/XmlSchemaCollection', @type=N'XMLSCHEMACOLLECTION', @enabled=False, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/XmlSchemaCollection', @level_name=N'XmlSchemaCollection', @condition_name=N'', @target_set_level_id=0


GO

DECLARE @policy_id INT
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'Table Names', @condition_name=N'No Spaces', @policy_category=N'', @description=N'', @help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=1, @is_enabled=True, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'Table Names_ObjectSet'
SELECT @policy_id


GO

В SQL Server 2012 и 2014 это дает ожидаемые результаты:

CREATE TABLE [test table]
(Id INT NULL)

Политика «Табличные имена» была нарушена «SQLSERVER: \ SQL \ LSRSQL07 \ SQL2012 \ Databases \ test \ Tables \ dbo.test table». Эта транзакция будет отменена. Условие политики: '@Name NOT LIKE'% [-.]% 'И @Name NOT LIKE'% [^ A-Za-z0-9 [_]]% '' Описание политики: '' Дополнительная помощь: '': '' Заявление: 'CREATE TABLE [тестовая таблица] (Id INT NULL)'. Сообщение 3609, Уровень 16, Состояние 1, Процедура sp_syspolicy_dispatch_event, Строка 65 [Строка пакетного запуска 48] Транзакция завершилась в триггере. Пакет был прерван.

И если я запускаю следующий код, я не получаю ошибку:

CREATE TABLE [testtable]
(Id INT NULL)

Однако, если я запускаю какой-либо CREATE TABLEоператор с включенной политикой в ​​SQL Server 2016, я получаю следующую ошибку:

Политика «Имена таблиц» была нарушена «SQLSERVER: \ SQL \ LSRSQL07 \ SQL2016 \ Базы данных \ test \ Tables \ dbo.testtable». Эта транзакция будет отменена. Условие политики: '@Name NOT LIKE'%% '' Описание политики: '' Дополнительная справка: '': '' Инструкция: 'CREATE TABLE [testtable] (Id INT NULL)'. Сообщение 515, Уровень 16, Состояние 2, Процедура sp_syspolicy_execute_policy, Строка 69 [Строка пакетного запуска 44] Не удается вставить значение NULL в столбец 'target_query_expression', таблица 'msdb.dbo.syspolicy_policy_execution_history_details_internal'; столбец не допускает пустых значений. Вставить не удается. Заявление было прекращено.

В SQL Server 2016 я не могу создать какую-либо таблицу , независимо от того, соответствует она условию или нет.

Это SQL Server 2016, SP1, CU3.

Есть идеи по этому поводу?

Изменить: мне нужно, чтобы режим оценки был "На изменения: предотвратить"

Джон
источник

Ответы:

6

Протестировал сценарии на экземпляре SQL Server 2016 с пакетом обновления 1 (SP1) CU2, и политика работает, если для режима оценки установлено значение «При изменении: предотвратить». (есть ошибка , которая не позволяет вам оценивать политики, которые используют определенные аспекты).

Между тем, если вы используете политику только для имен таблиц, вы также можете попробовать фасет «Параметр таблицы» вместо «MultipartName» с той же конфигурацией ( @NAME NOT LIKE '% %').

Dragos
источник
Если я установил режим оценки «По требованию», он работает, но, если честно, я раньше не пробовал этого. Я бы предпочел иметь это при изменении: запретить людям создавать таблицы, а затем хранить хранимые процедуры, ссылающиеся на плохо именованные таблицы.
Джон
Для меня это не работает, чтобы установить режим оценки на «По требованию» и оценить политику вручную. Но это работает нормально, если для оценки задано значение «При изменении: предотвратить» и попытаться создать таблицы. Вы можете попытаться опубликовать проблему в Microsoft Connect, чтобы узнать, является ли это ошибкой или нет.
Драгош
Спасибо, @Dragos. Это происходит на любом столе, даже на тех, которые должны пройти условие?
Джон
Таблицы без пробелов в имени создаются успешно, а таблицы с пробелами завершаются ошибкой с нарушением политики.
Dragos
У нас та же проблема с хранимой процедурой и просмотром аспектов. Мы находимся на SQL 2016 SP1 CU3 (последняя версия). Как сказал Джон, это похоже на ошибку, но интересно, смог ли кто-нибудь найти обходной путь?
DBAuser