0

次のコード (ケース 1 ) を実行すると、カウントの値 2 が得られます。つまり、同じトランザクション内で、テーブルに対して行われた変更が表示されます。したがって、これは私が期待する方法で動作します。

ケース1

begin tran mytran
begin try

CREATE TABLE [dbo].[ft](
    [ft_ID] [int] IDENTITY(1,1) NOT NULL,
    [ft_Name] [nvarchar](100) NOT NULL
 CONSTRAINT [PK_FileType] PRIMARY KEY CLUSTERED 
(
    [ft_ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

INSERT INTO [dbo].[ft]([ft_Name])
VALUES('xxxx')
INSERT INTO [dbo].[ft]([ft_Name])
VALUES('yyyy')

select count(*) from [dbo].[ft]

commit tran mytran
end try
begin catch
rollback tran mytran
end catch

ただし、列を変更すると (トランザクション内に新しい列を追加するなど)、(self/same) トランザクションには表示されません (ケース 2 )。ft_ID という列のない製品テーブルがあり、同じトランザクションで列を追加して、それを読み取ろうとしているとします。

ケース 2

begin tran mytran
begin try

IF NOT EXISTS (
  SELECT * 
  FROM   sys.columns 
  WHERE  object_id = OBJECT_ID(N'dbo.Products') 
         AND name = 'ft_ID'
)
begin
alter table dbo.Products 
add ft_ID int null
end

select ft_ID from dbo.Products


commit tran mytran
end try
begin catch
rollback tran mytran
end catch

ケース 2を実行しようとすると、「Invalid column name 'ft_ID'」というエラーが表示されます。これは、新しく追加された列が同じトランザクション内で表示されないためです。

この食い違いはなぜ起こるのでしょうか?テーブルの作成はアトミック (ケース 1 ) であり、期待どおりに機能しますが、テーブルの変更はそうではありません。同じトランザクション内で行われた変更が下のステートメントに表示されないのはなぜですか (ケース 2 )。

4

2 に答える 2

2

コンパイルエラーが発生します。バッチが実行されることはありません。SQL Server がクエリを実行する方法を理解するを参照してください。トランザクションの可視性と境界は、あなたが見ているものとは何の関係もありません。

DDL と DML は常に別々のリクエストに分ける必要があります。詳細については説明しませんが、リカバリの仕組み上、同じトランザクションで DDL と DML を混在させると問題が発生するだけです。これについては私の言葉を信じてください。

于 2013-10-31T07:58:37.210 に答える
1

バッチの使用規則
...
テーブルを変更してから、同じバッチ内で新しい列を参照することはできません。

これを見る

別の方法として、子バッチを生成し、そこから新しい列を参照することもできます...

exec('select ft_ID from dbo.Products')

ただし、Remus が言ったように、特に 1 つの同じトランザクション内で、スキーマの変更とそのスキーマからのデータの選択には十分注意してください。トランザクションがなくても、このコードには副作用があります。この exec() 回避策をストアド プロシージャにラップすると、呼び出すたびに再コンパイルが行われます。運が悪いですが、それは単にそのように機能します。

于 2013-10-31T07:58:47.697 に答える