SQL Serverではnvarchar
の値はUnicodeコードポイントの文字列を表します。デフォルトではUTF-16を使用していますが、0xFFFF
を超える値はサロゲートペアとして表されます。nvarcharの比較で0x8FFFの意義は何ですか?
nvarchar
UDFパラメータに、特殊文字を含むデフォルトの文字列値を設定したかったのですが、 T-SQLでは文字列リテラルで16進エスケープシーケンスを使用できないため、CHAR()
またはNCHAR()
関数を使用してコードポイント値で文字を指定する必要がありますが、パラメータの既定値にはリテラルを使用する必要があります。NCHAR()
は使用できません。
CREATE FUNCTION DoSomething(
@foo nvarchar(50) = '\x0008', -- not supported by T-SQL syntax
@bar nvarchar(50) = NCHAR(8), -- forbidden: defaults must be a literal
@baz nvarchar(50) = 0x008 -- success!
)
私は比較範囲を表現するためのパラメータを変更したい、と私はデフォルト値はの最も広い-可能な範囲を表現したかった。しかし私は、SQL Serverはまた、そう、varbinary
からnvarchar
への暗黙的な変換を実行することを思い出しましたしたがって、私はOPTION(RECOMPILE)
または今は信用されていない(@foo IS NULL OR Table.Foo = @foo)
パターンを必要とせずに、検索機能に静的SQLを使用させます。
だから私はこれに私の機能を変更:
CREATE FUNCTION DoSomething(
@fooMin nvarchar(50) = 0x0000,
@fooMax nvarchar(50) = 0xFFFF
)
/* SELECT goes here */
WHERE
Foo BETWEEN @fooMin AND @fooMax
私は0xFFFF
は、私が構築したシステムでスローされた(実用的な)Unicodeテキストを収容するのに十分に高いだろう推論しました。
しかし、驚いたことに、BETWEEN
オペレータは常にfalse
を返しました。私は何かが上限のオペランドであるかもしれないかと思ったので、それを0x7FFF
に変更して正常に動作しました。
私は0x8FFF
を試してみましたが、それも機能しました。
ただし、0x9FFF
、次に0x9000
は失敗しました。
私が知っている限り、ユニコードでは0x8FFF
- 0x9000
の境界について特別なことはありません。 https://en.wikipedia.org/wiki/Plane_(Unicode)#/media/File:Roadmap_to_Unicode_BMP.svgとUTF-16サロゲートが0xD800
と0xDC00
で開始 - 遠く0x900
から:0xFFFF
と0x900
は、単にCJKエリア内の別のブロックであること - ウィキペディアは、基本多言語面が0x0000
を占めて報告します。 0x8000
境界が、他の境界あまりにも - だから、それだけで0x7FFF
ないようです
HELLO 0xFF yup HELLO 0x0FFF no HELLO 0x1000 no HELLO 0x6000 no HELLO 0x6FFF yup HELLO 0x7000 yup HELLO 0x7FFF yup HELLO 0x8000 no HELLO 0x8FFF yup HELLO 0x9000 no HELLO 0x9FFF no HELLO 0xFFFF no
:
SELECT N'HELLO', 0xFF, (CASE WHEN N'HELLO' BETWEEN 0x0000 AND 0xFF THEN 'yup' ELSE 'no' END) UNION ALL SELECT N'HELLO', 0x0FFF, (CASE WHEN N'HELLO' BETWEEN 0x0000 AND 0x0FFF THEN 'yup' ELSE 'no' END) UNION ALL SELECT N'HELLO', 0x1000, (CASE WHEN N'HELLO' BETWEEN 0x0000 AND 0x1000 THEN 'yup' ELSE 'no' END) UNION ALL SELECT N'HELLO', 0x6000, (CASE WHEN N'HELLO' BETWEEN 0x0000 AND 0x6000 THEN 'yup' ELSE 'no' END) UNION ALL SELECT N'HELLO', 0x6FFF, (CASE WHEN N'HELLO' BETWEEN 0x0000 AND 0x6FFF THEN 'yup' ELSE 'no' END) UNION ALL SELECT N'HELLO', 0x7000, (CASE WHEN N'HELLO' BETWEEN 0x0000 AND 0x7000 THEN 'yup' ELSE 'no' END) UNION ALL SELECT N'HELLO', 0x7FFF, (CASE WHEN N'HELLO' BETWEEN 0x0000 AND 0x7FFF THEN 'yup' ELSE 'no' END) UNION ALL SELECT N'HELLO', 0x8000, (CASE WHEN N'HELLO' BETWEEN 0x0000 AND 0x8000 THEN 'yup' ELSE 'no' END) UNION ALL SELECT N'HELLO', 0x8FFF, (CASE WHEN N'HELLO' BETWEEN 0x0000 AND 0x8FFF THEN 'yup' ELSE 'no' END) UNION ALL SELECT N'HELLO', 0x9000, (CASE WHEN N'HELLO' BETWEEN 0x0000 AND 0x9000 THEN 'yup' ELSE 'no' END) UNION ALL SELECT N'HELLO', 0x9FFF, (CASE WHEN N'HELLO' BETWEEN 0x0000 AND 0x9FFF THEN 'yup' ELSE 'no' END) UNION ALL SELECT N'HELLO', 0xFFFF, (CASE WHEN N'HELLO' BETWEEN 0x0000 AND 0xFFFF THEN 'yup' ELSE 'no' END)
そして私の結果:
は、ここに私のテストケースです。それがリトルエンディアンの代わりに、ビッグエンディアンとしてバイナリリテラルを解釈しているためかもしれないが、彼らはN'H'
より大きくしているので、その後**FF
で終わるリテラルのすべてがtrue
を返す場合
あなたは無視している*照合* SQLで*ソート順*を定義します。 *バイナリ*照合を強制すると、範囲比較の大部分は –
"*私が構築していたシステムでスローされた(実用的な)Unicodeテキストを収容するのに十分な0xFFFFと推測されます*東アジアのテキスト、絵文字、記号などを扱う必要はありません。UTF-16でサロゲートペアを必要とします。 –
パラメータをNULLにデフォルト設定し、その機能を内部的にチェックするのはどうでしょうか?次に、パラメータ宣言に実際の文字列リテラルは必要なく、宣言を変更することなく、時間の経過とともにデフォルトを変更することができます。 –