無法解決“SQL_Latin1_General_CP1_CI_AS”和“Latin1_General_CI_AI”之間的排序規則衝突
我們最近在執行儲存過程時開始收到以下錯誤:
System.Data.SqlClient.SqlException (0x80131904):**無法解決等於操作中“SQL_Latin1_General_CP1_CI_AS”和“Latin1_General_CI_AI”之間的排序規則衝突**。 EXECUTE 之後的事務計數表明 BEGIN 和 COMMIT 語句的數量不匹配。先前計數 = 0,目前計數 = 1。 在 System.Data.SqlClient.SqlConnection.OnError(SqlException 異常,布爾 breakConnection,Action`1 wrapCloseInAction) 在 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj,布爾呼叫者HasConnectionLock,布爾非同步關閉) 在 System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,SqlCommand cmdHandler,SqlDataReader dataStream,BulkCopySimpleResultSet bulkCopyHandler,TdsParserStateObject stateObj,Boolean & dataReady) 在 System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() 在 System.Data.SqlClient.SqlDataReader.get_MetaData() 在 System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds,RunBehavior runBehavior,字元串 resetOptionsString) 在 System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior,RunBehavior runBehavior,布爾 returnStream,布爾非同步,Int32 超時,任務和任務,布爾非同步寫入,SqlDataReader ds) 在 System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior,RunBehavior runBehavior,布爾 returnStream,字元串方法,TaskCompletionSource`1 完成,Int32 超時,任務和任務,布爾 asyncWrite) 在 System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior,RunBehavior runBehavior,布爾 returnStream,String 方法) 在 System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior 行為,字元串方法) 在 System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior 行為) 在 System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior 行為) 在 System.Data.Common.DbDataAdapter.FillInternal
線上檢查並觀察儲存過程時,我們發現在儲存過程中開發人員正在創建#Temp 表,並且可以通過使用正確的數據庫預設排序規則創建#Temp 表來解決該問題。
我們想知道這個排序規則是如何改變的,因為儲存過程早些時候工作正常,我們第一次收到這種錯誤。我們不斷為伺服器獲取 Windows/安全更新檔更新;這些更新可以修改數據庫的排序規則屬性嗎?
CREATE table #temp( Code varchar(5) COLLATE DATABASE_DEFAULT null, Amount decimal(11,2) null ) INSERT into #temp select PT.Code,(PT.Percentage/100*(@PAmount+@ICharge+@FCharges+(select CC from @temp where [IN] = @MyVar))) from PTax PT inner join tax T on PT.Code=T.Code where Code = @strCode and PId=@PId AND T.Flag =@CFlag INSERT INTO #temp SELECT T.Code,0 from Tax T where Flag =@CFlag AND T.Code not in (select Code from #temp) drop table #tempTaxes
@Solomon Rutzky 輸出到第一個查詢:
0 <Instance> SQL_Latin1_General_CP1_CI_AS 1 master SQL_Latin1_General_CP1_CI_AS 2 tempdb SQL_Latin1_General_CP1_CI_AS 3 model SQL_Latin1_General_CP1_CI_AS 4 msdb SQL_Latin1_General_CP1_CI_AS 6 CustomerDB Latin1_General_CI_AI
第二個查詢輸出:
Latin1_General_CI_AI
第三個查詢輸出:
Tax 2017-09-15 01:46:39.217 2017-09-15 01:46:39.217
歡迎任何建議。
讓我們看看可能性。第一個是伺服器的排序規則已更改。這不太可能,因為它需要重建系統數據庫。除非您有非常動態的環境,並且多個管理員以混亂的方式做事,否則我不會進一步考慮這一點。
第一和一半:數據庫是否可能已移動到另一個實例?如果您使用客戶端別名,則更改可以是透明的。
第二個是數據庫的排序規則發生了變化。這很簡單,只需要一個
alter database
命令。因此,檢查數據庫的目前排序規則和預期排序規則。他們匹配嗎?第三個是儲存過程本身被修改或重命名。也許曾經有明確的排序規則規範,但被刪除了。你有版本控制中的儲存過程嗎?
要查看儲存過程的最後修改日期,請查詢
sys.procedures
SELECT create_date, modify_date, name FROM sys.procedures;
據我所知,如果不進行審計,就很難在事後發現數據庫更改。如果您正在使用某種 CI 系統,請仔細檢查最近是否重新部署了數據庫或儲存過程。
與其他伺服器管理員和開發人員聊天也值得一試。
實例級排序規則被更改的可能性很小。這將需要完全中斷,並且會引起某些人的注意。
雖然數據庫級排序規則也極不可能發生更改,但它也無關緊要,因為排序規則不會影響此操作,假設
COLLATE DATABASE_DEFAULT
您的語句中的 foundCREATE table #temp
只是作為此錯誤的修復而添加的。我從你的陳述中假設:線上檢查時…我們發現…可以通過使用正確的數據庫預設排序規則創建#Temp 表來解決該問題。
影響此操作的因素(在添加 之前
COLLATE DATABASE_DEFAULT
)是:
- 的排序規則
tempdb
,它應該與實例級排序規則相同,並且- 與臨時表字元串列進行比較的字元串列的排序規則:
Tax.Code
這是因為錯誤發生在這裡:
AND T.Code not in (select Code from #temp)
我的猜測是,如果儲存過程最近沒有更改(即如果
COLLATE DATABASE_DEFAULT
最初存在並被刪除),那麼表中的Code
列可能Tax
已更新,無論是數據類型還是設置 NULL / NOT NULL,並且未指定COLLATE
關鍵字*,**並且*該列的原始排序規則確實與tempdb
. 我猜這是因為如果你執行這樣的事情:ALTER TABLE [Tax] ALTER COLUMN [Code] VARCHAR(10) NOT NULL;
然後該列的排序規則將更改為數據庫的預設排序規則,如果它不同的話。
Tax
因此,為了幫助縮小範圍,請使用以下三個查詢的結果更新問題(執行它們時,您需要位於包含表的數據庫中):SELECT sd.[database_id], sd.[name], sd.[collation_name] FROM sys.databases sd WHERE sd.[database_id] IN (1, 2, 3, 4, DB_ID()) UNION ALL SELECT 0 AS [database_id], '<Instance>' AS [name], SERVERPROPERTY('collation') ORDER BY [database_id];
和:
SELECT col.[collation_name] FROM sys.columns col WHERE col.[object_id] = OBJECT_ID(N'Tax') AND col.[name] = N'Code';
和:
SELECT tab.[name], tab.[create_date], tab.[modify_date] FROM sys.tables tab WHERE tab.[name] = N'Tax';