sql >> データベース >  >> RDS >> Sqlserver

nvarchar連結/インデックス/nvarchar(max)不可解な動作

    TLDR; これは、行間で文字列を連結するための文書化された/サポートされたアプローチではありません。動作する場合もありますが、取得する実行プランによっては失敗する場合もあります。

    代わりに、次の保証されたアプローチのいずれかを使用してください

    SQL Server 2017+

    SELECT @a = STRING_AGG([msg], '') WITHIN GROUP (ORDER BY [priority] ASC)
    FROM bla
    where   autofix = 0
    

    SQL Server 2005+

    SELECT @a = (SELECT [msg] + ''
                 FROM   bla
                 WHERE  autofix = 0
                 ORDER  BY [priority] ASC
                 FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)') 
    

    背景

    VanDerNorthによってすでにリンクされているKB記事には、次の行が含まれています

    集計連結クエリの正しい動作は未定義です。

    しかし、その後、決定論的な行動が可能であることを示しているように見える回避策を提供することにより、水を少し濁らせます。

    集計連結クエリから期待される結果を得るには、Transact-SQL関数または式をORDERBY句ではなくSELECTリストの列に適用します。

    問題のあるクエリは、ORDER BYの列に式を適用しません 条項。

    2005年の記事「SQLServerでの順序付けの保証...」は次のように述べています

    下位互換性の理由から、SQL Serverは、最上位のスコープでSELECT @p =@p + 1 ...ORDERBYタイプの割り当てをサポートしています。

    連結が期待どおりに機能するプランでは、式[Expr1003] = Scalar Operator([@x]+[Expr1004])を使用してスカラーを計算します。 並べ替えの上に表示されます。

    動作に失敗したプランでは、計算スカラーがソートの下に表示されます。この接続項目で説明されているように、2006年の式@x = @x + [msg] 行ごとに評価される並べ替えの下に表示されますが、すべての評価は、@xの事前割り当て値を使用して終了します。 。 2006年の別の同様のConnectItemで、Microsoftからの応答は問題の「修正」について述べました。

    この問題に関する後のすべてのConnectアイテム(および多くのアイテム)に対するMicrosoftの応答では、これは単に保証されていないことが示されています

    例1

    連結クエリの正確性については保証しません(特定の順序でデータを取得する変数の割り当てを使用するなど)。 SQL Server 2008では、プランの選択、テーブル内のデータなどに応じて、クエリ出力が変更される可能性があります。構文では、順序付き行の取得と変数の割り当てを組み合わせたSELECTステートメントを記述できますが、これを一貫して機能させる必要はありません。

    例2

    表示されている動作は仕様によるものです。 ORDER BY句を使用したクエリで代入演算(この例では連結)を使用すると、動作が未定義になります。これは、リリースごとに、またはクエリプランの変更により特定のサーバーバージョン内でさえも変更される可能性があります。回避策がある場合でも、この動作に依存することはできません。詳細については、以下のKB記事を参照してください。
    http://support.microsoft.com/kb/287515保証されるメカニズムは次のとおりです。

    1. カーソルを使用して特定の順序で行をループし、値を連結します
    2. ORDERBYを使用したxmlクエリに使用して連結値を生成します
    3. CLR集計を使用します(これはORDER BY句では機能しません)

    例3

    表示されている動作は、実際には仕様によるものです。これは、SQLがセット操作言語であることに関係しています。 SELECTlist内のすべての式(およびこれには割り当ても含まれます)は、出力行ごとに1回だけ実行されるとは限りません。実際、SQL queryoptimizerは、それらを可能な限り少ない回数実行しようとします。これにより、テーブル内の一部のデータに基づいて変数の値を計算するときに期待される結果が得られますが、割り当てる値が同じ変数の以前の値に依存する場合、結果はまったく予期しないものになる可能性があります。クエリオプティマイザが式をクエリツリーの別の場所に移動すると、評価される回数が少なくなる可能性があります(または、例の1つでは1回だけ)。これが、集計値の計算に「反復」タイプの割り当てを使用することをお勧めしない理由です。 XMLベースの回避策は...通常は顧客にとってうまく機能することがわかりました

    例4

    ORDER BYがなくても、@ var =@var+が複数の行に影響を与えるステートメントの連結値を生成することを保証するものではありません。式の右辺は、クエリの実行中に1回または複数回評価でき、前述の動作はプランによって異なります。

    例5

    SELECTステートメントを使用した変数の割り当ては、動作が未定義であるか、複数の行が生成された場合にプランに依存する独自の構文(T-SQLのみ)です。文字列の連結を行う必要がある場合は、SQLCLR集計またはFORXMLクエリベースの連結またはその他のリレーショナルメソッドを使用します。



    1. 文字セットと照合は正確にはどういう意味ですか?

    2. SQLiteで値に少なくとも1桁の数字が含まれているかどうかを検出する

    3. Azure仮想マシンでのSQLServer2014の実行

    4. 単一のMySQLデータベースへのリモートアクセスを許可する方法