今回の前提としては、データベースの照合順序に「Japanese_XJIS_140_CI_AS」を使用している環境となります。
このデータベースに対して、以下のようなデータを登録します。
DROP TABLE IF EXISTS T1 CREATE TABLE T1 (C1 varchar(2), C2 nvarchar(1)) INSERT INTO T1 VALUES('あ', N'あ') SELECT * FROM T1
これに対して、以下のようなインプットをアウトプットとして返す、シンプルな Python スクリプトの実行を行ってみます。
EXEC sp_execute_external_script @language =N'Python', @script=N'OutputDataSet = InputDataSet', @input_data_1 = N'SELECT C1, C2 FROM T1' WITH RESULT SETS((C1 varchar(2), C2 nvarchar(1)))
そうすると、以下のようなエラーが発生するかと。
メッセージ 39004、レベル 16、状態 20、行 1
‘sp_execute_external_script’ に HRESULT 0x80004004 を指定して実行中に、’Python’ スクリプト エラーが発生しました。
メッセージ 39019、レベル 16、状態 2、行 1
外部スクリプトエラーが発生しました:
Traceback (most recent call last):
File "<string>", line 2, in <module>
File "C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\PYTHON_SERVICES\lib\site-packages\revoscalepy\computecontext\RxInSqlServer.py", line 522, in rx_sql_satellite_pool_call
exec(inputfile.read())
File "<string>", line 3, in <module>
File "C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\PYTHON_SERVICES\lib\site-packages\revoscalepy\computecontext\RxInSqlServer.py", line 474, in rx_sql_satellite_call
rx_native_call("SqlSatelliteCall", params)
File "C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\PYTHON_SERVICES\lib\site-packages\revoscalepy\RxSerializable.py", line 19, in rx_native_call
ret = px_call(functionname, params)
UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0x82 in position 0: invalid start byte
Invalid BXL stream
外部スクリプトからの STDOUT メッセージ:
C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\PYTHON_SERVICES\lib\site-packages\revoscalepy
Python へのデータの連携ですが、全角文字 (ダブルバイト / マルチバイト文字) については、Unicode データ型で連携が必要となるようです。
半角文字のみを含んでいる場合は、varchar / char を使っていて問題ないのですが、全角文字を含んでいるようなデータを登録している場合は、単純に非 Unicode 文字列を、インプットのデータストリームとして渡してしまうとエラーになるようです。
先ほどのクエリであれば、以下のような修正が必要なようですね。。
EXEC sp_execute_external_script @language =N'Python', @script=N'OutputDataSet = InputDataSet', @input_data_1 = N'SELECT CAST(C1 AS nvarchar(2)) AS C1, C2 FROM T1' WITH RESULT SETS((C1 varchar(2), C2 nvarchar(1)))
データの文字列型を nvarchar / nchar で構成していれば問題はないのですが、そうでない場合、明示的にキャストをしてインプットデータとして渡しておく必要がありそうです。
これであれば、問題なく実行することができました。
英数の全角の場合、英語の照合順序を使用すると半角で登録されるようなケースもあるようで、テストについては、英数ではなく、漢字やかなを使って実施しておいた方がよさそうな感じもありました。
アウトプットのデータストリームに、日本語の文字列を返すことはできそうだったのですが、SQL Server の Python スクリプトの標準出力に日本語を出力しようとしても文字化けするようでしたので、SQL Server のスクリプト内でのデバックには少し気を付けておいた方がよさそうではありました。
文字コードがらみは面倒ですねぇ…。
Nice catch! will add this to the docs.
Jeannine Takaki
6 9月 17 at 11:23