Как добавить новый столбец с проверочным ограничением в таблицу с одним оператором таблицы ALTER? - PullRequest
0 голосов
/ 25 октября 2019

Я пишу небольшой инструмент, который генерирует некоторые операторы SQL для меня. Заявления выглядят так:

SET IMPLICIT_TRANSACTIONS ON;
BEGIN TRANSACTION x;

ALTER TABLE schema.MyTable ADD MyNewColumn INT DEFAULT(-7777);

--ALTER TABLE schema.MyTable ADD CONSTRAINT CHK_MyTable_MyNewColumn CHECK(MyNewColumn IN(1, 2, 3, 4, 5));

EXEC sp_addextendedproperty @name = N'MS_Description', @value = 'texttexttext',  
@level0type = N'Schema',   @level0name = 'schema',
@level1type = N'Table',    @level1name = 'MyTable',
@level2type = N'Column',   @level2name = 'MyNewColumn';

INSERT INTO schema.SomeOtherTable VALUES(1, 2, 3);
-- Other statements....

--ROLLBACK TRANSACTION x;
--COMMIT TRANSACTION x;

Имена таблиц и тому подобное происходят из интерфейса инструментов. строка с ADD CONSTRAINT завершается ошибкой с invalid column 'MyNewColumn' ... Я думаю, это из-за незафиксированной транзакции ... Но мне нужно, чтобы в случае сбоя некоторых других операторов столбец, ограничение и другие данные были удалены...

Итак ... Есть ли способ ADD новый столбец в существующей таблице и также ADD с именем CHECK CONSTRAINT для той же таблицы в одном выражении? Или у вас есть другие идеи, как справиться с этим?

Ответы [ 2 ]

1 голос
/ 25 октября 2019

Добавление большего контекста к моему комментарию: "Чтобы повлиять на столбец (например, INSERT в него, добавить расширенное свойство и т. Д., И т. Д.), Он должен быть в другом пакете. Даже фиксация транзакции выигранане изменяйте это. До того, как этот пакет будет завершен, вы не сможете делать "вещи" для этого столбца. DB <> Fiddle"

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

Взятьэтот пример:

CREATE TABLE dbo.MyTable (ID int);
GO

ALTER TABLE dbo.MyTable ADD MyColumn int DEFAULT (100);

INSERT INTO dbo.MyTable
VALUES(1,100);

Сбой с ошибкой ниже:

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

Однако если вы назовете столбцы, вы получите другую ошибку:

ALTER TABLE dbo.MyTable ADD MyColumn int DEFAULT (100);

INSERT INTO dbo.MyTable  (ID, MyColumn)
VALUES(1,100)

Неверное имя столбца 'MyColumn'.

Для SP sp_addextendedproperty, однако,проверка существования столбца откладывается до выполнения SP;в этот момент столбец будет существовать. Если вы попробуете следующее, вы не получите сообщение об ошибке:

CREATE TABLE dbo.MyTable (ID int);
GO

ALTER TABLE dbo.MyTable ADD MyColumn int DEFAULT (100);

EXEC sp_addextendedproperty @name = N'MS_Description', @value = 'texttexttext',  
                            @level0type = N'Schema',   @level0name = 'dbo',
                            @level1type = N'Table',    @level1name = 'MyTable',
                            @level2type = N'Column',   @level2name = 'MyColumn';

GO
INSERT INTO dbo.MyTable  (ID, MyColumn)
VALUES(1,100)

GO

DROP TABLE dbo.MyTable;

Что касается вашего CONSTRAINT, то возникнет та же проблема, что и INSERT. Он должен быть в отдельном пакете.

Один из способов сделать это - отложить компиляцию оператора, добавив также CONSTRAINT, используя sp_executesql:

ALTER TABLE schema.MyTable ADD MyNewColumn INT DEFAULT(-7777);

EXEC sp_executesql N'ALTER TABLE schema.MyTable ADD CONSTRAINT CHK_MyTable_MyNewColumn CHECK(MyNewColumn IN(1, 2, 3, 4, 5));';
1 голос
/ 25 октября 2019

Проблема не в незафиксированной транзакции, а в том, что весь пакет должен быть скомпилирован перед выполнением, а столбец, указанный в DDL, еще не существует.

Чтобы избежать ошибки, можно добавить столбеци ограничения в одном операторе:

ALTER TABLE dbo.MyTable
     ADD MyNewColumn INT DEFAULT(-7777)
    ,CONSTRAINT CHK_MyTable_MyNewColumn CHECK(MyNewColumn IN(1, 2, 3, 4, 5));

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

ALTER TABLE dbo.MyTable
     ADD MyNewColumn INT DEFAULT(-7777);
EXECUTE(N'ALTER TABLE dbo.MyTable ADD CONSTRAINT CHK_MyTable_MyNewColumn CHECK(MyNewColumn IN(1, 2, 3, 4, 5));');

Кроме того, я предлагаю вам удалить SET IMPLICIT_TRANSACTIONS ON;, поскольку в сценарии уже есть транзакция экспликации. В противном случае, вы все равно будете иметь незафиксированную транзакцию после COMMIT.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...