2016-05-20 16 views
2

私は簡単なクエリを実行しようとすると、Pythonでこのエラーメッセージが表示されます。そして、私はこのクエリを少し変更すると、その大丈夫です。だから、これはそれがどのように見えるかです:あなたが見ることができるよう、値がパラメータのみの場合はデータ型が不明です

ので
>>> import fdb 
>>> cnx = fdb.connect(dsn = "C:\data\REESTR.FDB", user = "sysdba", password = "masterkey") 
>>> cnx.begin() 
>>> cursor = cnx.cursor() 
>>> query = "SELECT CASE WHEN 'val_1' = 'val_1' THEN ? ELSE 'val_2' END AS TXT FROM TEST_TABLE" 
>>> dat = ('val_1',) 
>>> cursor.execute(query, dat) # this query works ok 
<fdb.fbcore.Cursor object at 0x0000000002FEC978> 
>>> # now let's change the query a liitle bit: 
>>> query = "SELECT CASE WHEN 'val_1' = 'val_1' THEN ? ELSE ? END AS TXT FROM TEST_TABLE" 
>>> dat = ('val_1', 'val_2',) 
>>> cursor.execute(query, dat) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "C:\Python34\lib\site-packages\fdb-1.6-py3.4.egg\fdb\fbcore.py", line 3573, in execute 
    self._ps = PreparedStatement(operation, self, True) 
    File "C:\Python34\lib\site-packages\fdb-1.6-py3.4.egg\fdb\fbcore.py", line 2182, in __init__ 
    "Error while preparing SQL statement:") 
    fdb.fbcore.DatabaseError: ('Error while preparing SQL statement:\n- SQLCODE: -804\n- 
    Dynamic SQL Error\n- SQL error code = -804\n- 
    Data type unknown', -804, 335544569) 

、私は、クエリのELSE一部のための1つの追加の準備の変数を追加しました。 THENパートの準備がうまくいくので、すべてが非常に奇妙に見えます。このクエリではフィールドを使用しないので、テーブルのスキーマについて私に尋ねることはできません。したがって、どのテーブルでもこの​​エラーを再現できます。

PROOF

enter image description here

+2

ヒント:テーブルのDDLを投稿したくない場合は、「このクエリでフィールドを使用しないので、テーブルのスキーマについて私に尋ねないかもしれませんあなたはテーブルでこのエラーを再現することができます。この場合は、代わりに 'RDB $ DATABASE'を使用して回避することもできます。他の場合は、テーブルが関連する場合は必要最小限のDDLを投稿するだけです。 –

+0

チップをありがとう! – Jacobian

答えて

3

問題はFirebirdのは、(得られた式の)パラメータのデータ型を知っている必要があることです。それは、それを行うにはいくつかの戦略を持っていることがCHAR(4)としてELSE 'val_2'に基づくCASE式の型を推論

CASE WHEN 'val_1' = 'val_1' THEN ? ELSE 'val_2' END 

とそう、そのTHEN ?におけるパラメータもCHAR(4)です。

しかし、パラメータの又は全体としてCASE式の型を推論する情報を有していない

CASE WHEN 'val_1' = 'val_1' THEN ? ELSE ? END 

を提示します。たとえば、これがWHERE句だった場合は、式が比較される列に基づいて推論できます。右のタイプ(これはFirebirdの2.5以降で動作します)への明示的なパラメータのFirebirdのは、あなたが1つ(または両方)をキャストしてヒントを与える必要が支援するため

CASE WHEN 'val_1' = 'val_1' THEN CAST(? AS CHAR(4)) ELSE ? END 

私は(信じているが、古いFirebirdのバージョンでは、あなたがそれCHAR(5)作るために

CASE WHEN 'x' <> 'x' THEN 'DUMMY' WHEN 'val_1' = 'val_1' THEN ? ELSE ? END 

のようなものを使用することができるかもしれないということ)をテストしませんでした。

+0

ありがとう、マーク!あなたの答えはすべてを説明しています!しかし、変数が動的で、文字列パラメータの正確な長さを事前に知っていないので、ある時点でval_1になり、別の瞬間にblablablaになることがありますか?それをキャストする正しい方法は何ですか? – Jacobian

+0

@Jacobian残念なことにFirebirdの限界の1つですが、文の準備時にサイズを知る必要があります:予想されるすべての値に対して十分な大きさにキャストする必要があります( 'CASE WHEN 'val_1' = ' val_1 'THEN?ELSE' val_2 'END'、それ以外の場合は 'CHAR(4)'に制限します)。 –

+0

ああ、そうだ。私はそれが本当に不自然だとわかります。議論中のクエリとこのクエリの準備文は、MySQL、SQlite、MSSQL、Oracle、Postgresでうまく機能します。しかし、時々、Oracle 11などでTOPやLIMITが不足しているなど、データベースが異なるデータベースがいくつかあります。そして今、私はFirebirdでそのような不快なものを見ています。 – Jacobian

関連する問題