排序規則衝突…無法使用 dbo.sysdac_instances
將數據庫遷移到具有預設排序規則 Latin1_General_CI_AS 的新 2014 伺服器後,但大多數數據庫的排序規則為 Latin1_General_BIN,嘗試導入 Excel 電子表格會引發以下錯誤:
我已經將 sysdac_instances 跟踪到 msdb,它是一個系統視圖,直接查詢它會給出相同的錯誤。我希望有人能夠為我指出解決這個問題的直接方法的方向嗎?
不過奇怪的是,通過 SSMS 2008 執行導入是可行的。
sysdac_instances
視圖定義如下:CREATE VIEW [dbo].[sysdac_instances] AS SELECT -- this must be locked down because we use instance_id visability as a security gate case when (dbo.fn_sysdac_is_currentuser_sa() = 1) then dac_instances.instance_id when sd.owner_sid = SUSER_SID() then dac_instances.instance_id else NULL end as instance_id, dac_instances.instance_name, dac_instances.type_name, dac_instances.type_version, dac_instances.description, case when (dbo.fn_sysdac_is_currentuser_sa() = 1) then dac_instances.type_stream when sd.owner_sid = SUSER_SID() then dac_instances.type_stream else NULL end as type_stream, dac_instances.date_created, dac_instances.created_by, dac_instances.instance_name as database_name FROM sysdac_instances_internal dac_instances LEFT JOIN sys.databases sd ON dac_instances.instance_name = sd.name
視圖
instance_name
對sys.databases.name
列執行連接。由於 的列定義sysdac_instances_internal.instance_name
未指定排序規則,因此它將假定 msdb 數據庫的排序規則。也許您從排序規則所在的實例中恢復了 msdb
Latin1_General_BIN
,這會導致排序規則衝突。如果是這種情況,您需要重新創建 MSDB 數據庫,因為它的排序規則無法更改。
雖然@Max關於a)這個錯誤的根本原因是正確
msdb
的(恢復的數據庫的排序規則與伺服器的預設排序規則不匹配,該排序規則用於設置欄位的排序規則name
- 欄位的master.sys.sysdbreg
實際來源),並且b)理想情況下,您將重建以具有與伺服器預設值(即)匹配的排序規則,有兩種短期解決方案可以讓您的導入工作,直到您可以實施理想的解決方案(是的,我嘗試了兩者並且它們確實有效: -):name``sys.databases``msdb``Latin1_General_CI_AS
- 更改
dbo.sysdac_instances
View 的定義以顯式聲明由於預設排序規則優先行為而將繞過衝突的排序規則:ALTER VIEW [dbo].[sysdac_instances] AS SELECT -- this must be locked down because we use instance_id visability as a security gate case when (dbo.fn_sysdac_is_currentuser_sa() = 1) then dac_instances.instance_id when sd.owner_sid = SUSER_SID() then dac_instances.instance_id else NULL end as instance_id, dac_instances.instance_name, dac_instances.type_name, dac_instances.type_version, dac_instances.description, case when (dbo.fn_sysdac_is_currentuser_sa() = 1) then dac_instances.type_stream when sd.owner_sid = SUSER_SID() then dac_instances.type_stream else NULL end as type_stream, dac_instances.date_created, dac_instances.created_by, dac_instances.instance_name as database_name FROM sysdac_instances_internal dac_instances LEFT JOIN sys.databases sd ON dac_instances.instance_name = sd.name COLLATE Latin1_General_CI_AS
我使用直接從數據庫中提取了該定義
SELECT OBJECT_DEFINITION(OBJECT_ID('dbo.sysdac_instances'));
,然後COLLATE
在末尾添加了該子句。我
Latin1_General_CI_AS
在子句中使用了排序規則COLLATE
來添加,而不是二進制排序規則,因此這個操作(即匹配數據庫名稱)的行為類似於任何其他比較sys.databases.name
(當然,不使用 COLLATE 子句覆蓋;- ) 2. 更改相關欄位的排序規則:USE [msdb]; ALTER TABLE dbo.[sysdac_instances_internal] DROP CONSTRAINT [UQ_sysdac_instances_internal]; ALTER TABLE dbo.[sysdac_instances_internal] ALTER COLUMN [instance_name] sysname COLLATE Latin1_General_CI_AS NOT NULL; ALTER TABLE dbo.[sysdac_instances_internal] ADD CONSTRAINT [UQ_sysdac_instances_internal] UNIQUE NONCLUSTERED ([instance_name] ASC);
msdb
在這兩個選項之間,#1(即更改視圖)對使用基礎表的數據庫中的其他內容產生不利影響的可能性最小。如果您正在考慮更新實例和數據庫的排序規則,請參閱我的以下文章:
更改所有使用者數據庫中的實例、數據庫和所有列的排序規則:可能出了什麼問題?
其他注意事項:
- 我猜想在 SSMS 2008 中導入很可能是因為它的程式碼沒有引用這個特定的視圖。我想不出任何其他可以解釋這種行為的差異。
- 使用二進制排序規則時,最好使用較新的
BIN2
排序規則,而不是棄用的BIN
排序規則。- 如果可能,最好使用特定排序規則的最新版本,並選擇以 結尾的它的變體(
_SC
如果可用)。對於您的新伺服器,更好的選擇是:Latin1_General_100_CI_AS_SC
.- 這是為什麼我們需要有一個類似於
DATABASE_DEFAULT
但在實例級別工作的特殊排序規則的另一個例子INSTANCE_DEFAULT
——這樣就可以對這類問題有一個通用的解決方案。這將允許msdb.dbo.sysdac_instances_internal
使用以下方法創建表:... [instance_name] sysname COLLATE INSTANCE_DEFAULT, ...
或者,視圖最後可能是這樣的
msdb.dbo.sysdac_instances
:LEFT JOIN sys.databases sd ON dac_instances.instance_name = sd.name COLLATE INSTANCE_DEFAULT
所以請投票支持以下建議:
添加特殊排序規則 INSTANCE_DEFAULT 以像 COLLATE DATABASE_DEFAULT 一樣工作,但使用實例的預設排序規則