簡體   English   中英

“SQL_Latin1_General_CP1_CI_AS”與“Modern_Spanish_CI_AS”之間的歸類沖突等於操作

[英]Collation conflict between “SQL_Latin1_General_CP1_CI_AS” and “Modern_Spanish_CI_AS” in the equal to operation

我正在從SQL SERVER 2008 R2到WINDOWS AZURE創建這個SQL函數,但我不知道如何解決這個問題。

消息468,級別16,狀態9,過程GetObjectivesByTest,行69無法解決等於操作中“SQL_Latin1_General_CP1_CI_AS”和“Modern_Spanish_CI_AS”之間的排序規則沖突。

CREATE FUNCTION [dbo].[GetObjectivesByTest](@testId smallint)
RETURNS 
@res TABLE 
(
    -- Add the column definitions for the TABLE variable here
    ObjectiveId smallint NOT NULL,
    Name nvarchar(50) NOT NULL,
    Expectations nvarchar(400) NULL,
    [Level] nvarchar(5) NOT NULL,
    ParentId smallint NULL,
    LearningSystem nvarchar(30) NULL,
    [Rank] tinyint NULL
)
AS
BEGIN
DECLARE @string VARCHAR(MAX)
SELECT @string = OBJECTIVES FROM TESTS WHERE TestId = @testId

DECLARE @temp TABLE
(  
  ColumnA NVARCHAR(50),
  ColumnB NVARCHAR(500),
  ID INT IDENTITY(1,1)
)

INSERT INTO @temp (ColumnA, ColumnB) VALUES ('', @string)

DECLARE @idx INT, @cnt INT
SET @idx = 1
SELECT @cnt = COUNT(*) FROM @temp

DECLARE @SplitStr nvarchar(1000),
        @SplitChar nvarchar(5), 
        @Columns VARCHAR(50)
SET @SplitChar = ','

WHILE @idx <= @cnt BEGIN
      SELECT @SplitStr = ColumnB
      FROM @temp
      WHERE id = @idx

      DECLARE @RtnValue table 
      (
        ColumnName VARCHAR(50),
        Data VARCHAR(50)
      ) 

      Declare @Count int
      Set @Count = 1

      While (Charindex(@SplitChar,@SplitStr)>0) Begin
        Insert Into @RtnValue (ColumnName,Data)
        Select @Columns, Data = ltrim(rtrim(Substring(@SplitStr,1,Charindex(@SplitChar,@SplitStr)-1))) 

        Set @SplitStr = Substring(@SplitStr,Charindex(@SplitChar,@SplitStr)+1,len(@SplitStr))
        Set @Count = @Count + 1
      End

      Insert Into @RtnValue (ColumnName,Data)

      Select @Columns,Data = ltrim(rtrim(@SplitStr))
      SET @idx = @idx + 1 
END

INSERT @RES   // here is appointing the error
SELECT C.*
FROM Objectives AS C
INNER JOIN OBJECTIVES AS B ON (C.ParentId = B.ObjectiveId)
INNER JOIN OBJECTIVES AS A ON (B.ParentId = A.ObjectiveId)
where C.Rank = 3 AND B.Rank = 2 AND A.Rank = 1 AND
      A.LearningSystem + ' ' + A.Level + '.' + C.Level IN (SELECT Data FROM @RtnValue)

    RETURN 
END

我對這個問題一無所知,如何解決這種不兼容問題。 提前致謝。

數據庫排序規則(@ RtnValue.Data)與Objectives.LearningSysten中使用的排序規則之間存在排序規則不匹配。

最快的解決方案可能是在@RtnValue中明確聲明排序規則:

DECLARE @RtnValue table
(
    ColumnName VARCHAR(50),
    Data VARCHAR(50) COLLATE [insert required collation name]
)

這是一個快速修復,但是,您應該檢查數據庫和表列級別上的排序規則的正確使用。

排序規則定義SQL Server如何比較字符串值,並在SQL Server中的各個級別指定:

  1. 服務器默認排序規則:在安裝SQL Server時將其指定為選項,並定義將用於任何新數據庫以及主數據庫和臨時數據庫的排序規則。
  2. 數據庫默認排序規則:在創建新數據庫時指定。 如果未指定,將使用服務器默認排序規則。 此排序規則用於在數據庫中創建的任何字符串值列(CHAR,VARCHAR,NCHAR,NVARCHAR)。 此排序規則還用作表值變量中任何字符串值變量和字符串列的缺省值。
  3. 列排序規則:這是在列級別指定的,並指定用於特定列的排序規則。

你應該記住的一些事情:

  1. 將數據庫還原到新服務器時,服務器不會將數據庫的排序規則轉換為服務器的排序規則。
  2. 使用的默認排序規則在不同的上下文中有所不同:T-SQL中的表值變量和變量使用數據庫默認值,TempDB列使用服務器默認值。

您不能隱式地將字符串值與不同的排序規則進行比較。 雖然正確的做法是使用正確的整理,但有一些簡單的解決方法。 以下是您的選擇,按復雜程度遞增:

  • 如果這是一個孤立的查詢,其中臨時表字符串列與數據庫中的相應值進行比較,或者您很急,只是想讓它工作,您可以在WHERE子句中指定排序規則。 只要將數據庫中的字符串值與T-SQL查詢中的局部變量進行比較,就需要執行此操作:

     WHERE C.Rank = 3 AND B.Rank = 2 AND A.Rank = 1 AND A.LearningSystem + ' ' + A.Level + '.' + C.Level COLLATE SQL_Latin1_General_CP1_CI_AS IN (SELECT Data COLLATE SQL_Latin1_General_CP1_CI_AS FROM @RtnValue) 
  • 您的下一個選項,也許是最佳解決方案,是匹配數據庫默認排序規則和數據庫中所有字符串列中使用的排序規則。 更改數據庫排序ALTER DATABASE MyDB COLLATE SQL_Latin1_General_CP1_CI_AS就像調用ALTER DATABASE MyDB COLLATE SQL_Latin1_General_CP1_CI_AS一樣簡單,如MSDN Technet文章設置或更改數據庫排序規則中所述 但是,它不會為您更改數據庫中列的排序規則。 但是,您可以使用系統表生成一個腳本來執行此操作。 我的機器上沒有SQL Server,所以我無法對此進行測試,但這會給你一般的想法。 運行腳本,將結果復制到SQL窗格中,然后運行它。

     WITH cte AS (SELECT o.name AS TableName, c.name AS ColumnName, t.name AS TypeName, c.max_length AS MaxLen FROM sys.objects o INNER JOIN sys.columns c ON o.object_id = c.object_id INNER JOIN sys.types t ON t.system_type_id = c.system_type_id WHERE o.type = 'U' AND t.name IN ('char', 'nchar', 'varchar', 'nvarchar')) SELECT 'ALTER TABLE ' + TableName + ' ALTER COLUMN ' + ColumnName + ' ' + TypeName + '(' + CAST(CASE WHEN SUBSTRING(TypeName, 1, 1) = 'n' THEN MaxLen/2 ELSE MaxLen END AS VARCHAR) + ') COLLATE SQL_Latin1_General_CP1_CI_AS' FROM cte 

請注意,使用此解決方案,您仍需要為臨時表中使用的任何列指定排序規則,無論這些列是在存儲過程還是原始T-SQL命令的上下文中。 但是,這是一種很好的做法,因為如果將此數據庫部署到已擁有自己的數據庫服務器且希望使用同一服務器的客戶,則不能指望他們必須更改其服務器的默認排序規則。

  • 最后,您還可以更改服務器排序規則以匹配數據庫和所有列的排序規則。 這是一個痛苦的屁股,但可以使用原始安裝媒體集完成,如MSDN Technet站點上的設置和更改 MSDN Technet站點上的服務器排序規則所述。

這些都很難看。 我知道有兩種方法可以解決這個問題,而且都不是那么優雅:


更改其中一個數據庫的排序規則以匹配另一個: http//msdn.microsoft.com/en-us/library/ms175835(v = sql.105).aspx

或者更改查詢/表中每列的排序規則以匹配目標數據庫: http//msdn.microsoft.com/en-us/library/ms190920(v = sql.105).aspx

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM