Sql-Server

無法解決“SQL_Latin1_General_CP1_CI_AS”和“Latin1_General_CI_AI”之間的排序規則衝突

  • August 3, 2018

我們最近在執行儲存過程時開始收到以下錯誤:

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)是:

  1. 的排序規則tempdb,它應該與實例級排序規則相同,並且
  2. 與臨時表字元串列進行比較的字元串列的排序規則: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';

引用自:https://dba.stackexchange.com/questions/213867