我在 SQL Server 2019 中有一個表,它定義如下:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING OFF
GO
CREATE TABLE [dbo].[productionLog2](
[id] [int] IDENTITY(1,1) NOT NULL,
[itemID] [binary](10) NOT NULL,
[version] [int] NOT NULL,
CONSTRAINT [PK_productionLog2] PRIMARY KEY CLUSTERED
(
[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]
GO
該表將記錄生產的專案,它是一個檢查點,以避免(itemId,version)在version>0 的情況下生成重復的專案。換句話說,我們不應該有相同itemId和的行version(此規則僅適用于version大于 0 的行)。
所以我添加了以下約束作為過濾后的索引:
設定 ANSI_PADDING 關閉
CREATE UNIQUE NONCLUSTERED INDEX [UQ_itemID_ver] ON [dbo].[productionLog2]
(
[itemID] ASC,
[version] ASC
)
WHERE ([version]>=(0))
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
問題是當我想執行包含多個命令的事務時,例如下面一個使用 C OLE API(對于 VC V7/Visual Studio 2000),在將上述索引添加到表后插入失敗,盡管插入命令本身會運行單獨在 SQL Server 管理作業室中,沒有錯誤。
C 遵循這樣的順序:
--begin C transaction
--excute sub-command 1 in C
SELECT ISNULL(MAX(version),-1)
FROM [dbo].[productionLog2]
WHERE [itemID]=0x01234567890123456789
--increase version by one inside C code
-- consider fox example max version is 9
-- will use 10 for next version insertion
--excute sub-command 2 in C
INSERT INTO [dbo].[productionLog2]([itemID] ,[version] )
VALUES (0x01234567890123456789,10);
--end C transaction
上面的事務在到達插入命令時將無法運行,但下面的腳本第一次運行沒有錯誤(對于下一次運行,它將由于約束而失敗):
INSERT INTO [dbo].[productionLog2]([itemID] ,[version] )
VALUES (0x01234567890123456789,10);
你能想象定義的約束有什么問題嗎?或者是什么原因導致它會避免運行 C 命令但在 SSMS 中運行良好?
PS在此之前,我沒有要求添加WHERE ([version]>=(0))我的 INDEX,所以我使用了 UNIQUE 約束,但是由于我想過濾 CONSTRAINT,我將約束更改為帶有過濾器的 INDEX,并且在我的代碼執行期間進行此更改之前沒有任何問題。
uj5u.com熱心網友回復:
CREATE INEX 檔案中列出了過濾索引所需的會話 SET 選項:
------------------------- ---------------- ---------------------- ------------------------------- --------------------------
| SET options | Required value | Default server value | Default OLE DB and ODBC value | Default DB-Library value |
------------------------- ---------------- ---------------------- ------------------------------- --------------------------
| DB-Library value | | | | |
| ANSI_NULLS | ON | ON | ON | OFF |
| ANSI_PADDING | ON | ON | ON | OFF |
| ANSI_WARNINGS* | ON | ON | ON | OFF |
| ARITHABORT | ON | ON | OFF | OFF |
| CONCAT_NULL_YIELDS_NULL | ON | ON | ON | OFF |
| NUMERIC_ROUNDABORT | OFF | OFF | OFF | OFF |
| QUOTED_IDENTIFIER | ON | ON | ON | OFF |
------------------------- ---------------- ---------------------- ------------------------------- --------------------------
這些由現代 SQL Server API 正確設定,但您似乎有舊代碼和/或驅動程式。
將這些SET陳述句添加到使用過濾索引修改表的 T-SQL 批處理中:
SET ANSI_NULLS, ANSI_PADDING, ANSI_WARNINGS, ARITHABORT,CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER ON;
SET NUMERIC_ROUNDABORT OFF;
對于根本不設定會話選項的過時驅動程式,SET將使用默認資料庫選項。這些主要設定OFF為向后兼容。下面的腳本將設定過濾索引所需的資料庫默認值,但同樣,驅動程式或會話的顯式設定將覆寫這些。
ALTER DATABASE YourDatabase SET ANSI_NULLS ON;
ALTER DATABASE YourDatabase SET ANSI_PADDING ON;
ALTER DATABASE YourDatabase SET ANSI_WARNINGS ON;
ALTER DATABASE YourDatabase SET ARITHABORT ON;
ALTER DATABASE YourDatabase SET CONCAT_NULL_YIELDS_NULL ON;
ALTER DATABASE YourDatabase SET QUOTED_IDENTIFIER ON;
ALTER DATABASE YourDatabase SET NUMERIC_ROUNDABORT OFF;
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/393891.html
