仅参数作为值的 case 表达式中的数据类型未知

Data type unknown in case expression with only parameters as values

当我尝试执行一个简单的查询时,我在 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 部分添加了一个额外的准备变量。这一切看起来都很奇怪,因为 THEN 部分的准备工作很好。您可能不会问我关于 table 的架构,因为我没有在此查询中使用任何字段。因此,您可以使用任何 table.

重现此错误

证明

问题是 Firebird 需要知道参数(以及结果表达式)的数据类型。它有几种策略可以做到这一点,因此

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

根据ELSE 'val_2'推断CASE表达式的类型为CHAR(4),因此THEN ?中的参数也是CHAR(4).

但是当出现

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

它没有信息来推断参数或整个 CASE 表达式的类型。例如,如果这是一个 WHERE 子句,它可以根据表达式所比较的列来推断它。

为了帮助 Firebird,您需要通过将一个(或两个)参数显式转换为正确的类型来给出提示(这适用于 Firebird 2.5 及更高版本):

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

我相信(但未测试)在较旧的 Firebird 版本中,您可以使用类似

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

使其成为 CHAR(5).