3

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

この問題についてはわかりませんでした。その非互換性を修正するにはどうすればよいですか。前もって感謝します。

4

3 に答える 3

7

データベースの照合 (@RtnValue.Data) と Objectives.LearningSysten で使用される照合の間に照合の不一致があります。

最も簡単な解決策は、@RtnValue で照合を明示的に宣言することです。

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

これは簡単な修正ですが、データベースとテーブルの列レベルで照合が正しく使用されていることを確認する必要があります。

于 2012-12-29T18:16:27.470 に答える
4

照合は、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データベース照合順序の変更は、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 コマンドのコンテキスト内にあるかどうかにかかわらず、一時テーブルで使用されるすべての列の照合順序を指定する必要があることに注意してください。ただし、このデータベースを、独自のデータベース サーバーを既に持っていて、同じサーバーを使用したい顧客に展開する場合、サーバーの既定の照合順序を変更する必要があるとは考えられないため、これは適切な方法です。

于 2012-12-31T11:53:39.160 に答える
0

これらは醜いです。私はこれを解決する 2 つの方法を知っていますが、どちらもそれほどエレガントではありません:


データベースの 1 つの照合順序を変更して、他のデータベースと一致させます。 105).aspx

または、クエリ/テーブルの各列の照合順序を変更して、宛先データベースに一致させます: http://msdn.microsoft.com/en-us/library/ms190920(v=sql.105).aspx

于 2012-12-29T18:19:36.787 に答える