2012-12-29 25 views
3

我正在從SQL SERVER 2008 R2創建SQL函數到WINDOWS AZURE,但我不知道如何解決這個問題。「SQL_Latin1_General_CP1_CI_AS」和「Modern_Spanish_CI_AS」之間的排序衝突等於

消息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 

我沒有對這個問題的想法,我怎麼能解決這個問題的不兼容。 在此先感謝。

回答

7

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

最快的解決方案可能是顯式聲明的排序規則@RtnValue:

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

這是一個快速解決方案,但是,你應該檢查正確使用排序規則對數據庫和表列級。

2

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

  1. Server的默認合作llation:在安裝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) 
    
  • 你的下一個選擇,也可能是最好的解決辦法,是相匹配的數據庫默認排序規則和數據庫中所有字符串列中使用的排序規則。正如MSDN Technet文章Set or Change the Database Collation中所述,更改數據庫歸類與調用ALTER DATABASE MyDB COLLATE SQL_Latin1_General_CP1_CI_AS一樣簡單。然而,它不會爲你做的是更改數據庫中列的排序規則。但是,您可以使用系統表生成腳本來爲您執行此操作。我的機器上沒有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站點上的Setting and Changing the Server Collation上MSDN Technet站點上所述。
+0

謝謝彼得。你拯救了我的一天。原來列整理沒有被改變。 – gaurav

相關問題