No PostgreSQL eu posso criar uma tabela com alguns dados de teste e, em seguida, em uma transação migrá-la para uma nova coluna de um tipo diferente, resultando em uma reescrita de tabela COMMIT
,
CREATE TABLE foo ( a int );
INSERT INTO foo VALUES (1),(2),(3);
Seguido por,
BEGIN;
ALTER TABLE foo ADD COLUMN b varchar;
UPDATE foo SET b = CAST(a AS varchar);
ALTER TABLE foo DROP COLUMN a;
COMMIT;
No entanto, essa mesma coisa no SQL Server da Microsoft parece gerar um erro. Compare este db fiddle de trabalho , onde o ADD
comando (coluna) está fora da transação,
-- txn1
BEGIN TRANSACTION;
ALTER TABLE foo ADD b varchar;
COMMIT;
-- txn2
BEGIN TRANSACTION;
UPDATE foo SET b = CAST( a AS varchar );
ALTER TABLE foo DROP COLUMN a;
COMMIT;
para este violino db que não funciona,
-- txn1
BEGIN TRANSACTION;
ALTER TABLE foo ADD b varchar;
UPDATE foo SET b = CAST( a AS varchar );
ALTER TABLE foo DROP COLUMN a;
COMMIT;
Mas em vez disso erros
Msg 207 Level 16 State 1 Line 2
Invalid column name 'b'.
Existe alguma maneira de tornar esta transação visível, no que diz respeito ao DDL, se comportar como o PostgreSQL?
De um modo geral, não. O SQL Server compila todo o lote no escopo atual antes da execução, portanto, as entidades referenciadas precisam existir (recompilações em nível de instrução também podem ocorrer posteriormente). A principal exceção é a resolução de nomes adiada , mas isso se aplica a tabelas, não a colunas:
As soluções alternativas comuns envolvem código dinâmico (como na resposta de Joe ) ou separando o DML e o DDL em lotes separados.
Para este caso específico, você também pode escrever:
Você ainda não poderá acessar a coluna renomeada
b
no mesmo lote e escopo, mas ela faz o trabalho.Com relação ao SQL Server, existe uma escola de pensamento que diz que misturar DDL e DML em uma transação não é uma boa ideia. Houve erros no passado em que isso resultou em log incorreto e um banco de dados irrecuperável. No entanto, as pessoas fazem isso, especialmente com mesas temporárias. Isso pode resultar em um código bastante difícil de seguir.
É isso que você está procurando?
Para a declaração "geralmente não" da resposta de Paul White, espero que o seguinte ofereça uma resposta direta à pergunta, mas também sirva para mostrar as limitações sistêmicas de tal processo e o afasta de métodos que não facilitam o gerenciamento e expõem riscos.
Agora, para aqueles que duvidam que isso funcione, provavelmente não funciona na sua instância, mas algumas versões como 2017 podem realmente funcionar! Aqui está a prova:
[CÓDIGO DE TESTE - PODE não funcionar em muitas versões do SQL Server]
[CONCLUSÃO]
Então, sim, você pode executar DDL e DML no mesmo lote para determinadas versões ou patches do SQL Server como @AndriyM - dbfiddle no SQL 2017 aponta, mas nem todos os DML são suportados e não há garantia de que isso sempre será o caso. Se funcionar, pode ser uma aberração da sua versão do SQL Server e isso pode causar problemas dramáticos à medida que você corrige ou migra para novas versões.
[CRÉDITO EXTRA]
Quanto à instrução EXISTS, como Paul afirmou, existem muitos outros meios para validar o código antes de passar para a próxima etapa do seu código.