6

我正在使用 dbExpress 组件(Delphi 7)开发一个数据库程序。通过以下组件从数据库中检索数据:TSQLDataSet -> TDataSetProvider -> TClientDataSet -> TDatasource -> TDBEdit。到目前为止,该表单已正常工作。TSQLDataset 中的查询是

select id, name, byteken, timeflag from scales where id = :p1

我在数据库表中添加了一个大的(2048)varchar 字段;当我将此字段添加到上述查询(并将 TDBMemo 或 TDBRichEdit)连接到 TDatasource)时,当我尝试编辑新文本字段中的值时收到以下消息

Unable to find record. No key specified.

当表单上没有 TDBMemo 时(但查询中有 varchar 字段),我得到了同样的错误。一旦我从查询中删除 varchar 字段,一切都会再次正常工作。

这个问题的原因可能是什么?

==== 更多信息 ====

我现在已经在表单中定义了持久字段。保存表键的字段将其提供者标志设置为 [pfInUpdate,pfInWhere,pfInKey],而所有其他字段的标志设置为 [pfInUpdate,pfInWhere]。这并不能解决问题。

持久字段是在客户端数据集上定义的。当我在 TSQLDataSet 上定义它们时,不会出现有关“未指定键”的错误消息。该程序仍然会发出此错误消息(我之前忽略了):

EDatabase error: arithmetic exception, numeric overflow or string truncation

大字符串字段在“displaywidth”和“size”中具有正确的值。

==== 更多信息 ====

我重写了表单以使用非数据感知组件。一个查询从数据库中检索数据(使用与我在 TSQLDataSet 中使用的完全相同的查询字符串);然后将数据传输到控件。在用户按下表单上的 OK 按钮后,数据将通过另一个执行更新或插入的查询传递回数据库。由于这可以正常工作,我看不出数据感知组件有什么问题。

==== 又一个信息片段 ====

我在 Stack Overflow 上发现了这个问题,似乎解决了类似的问题。我将查询更改为

select id, name, name, byteken, timeflag, 
cast (constext as varchar (2048)) as fconstext
from scales
where id = :p1

并将 dbMemo 的数据字段设置为“fconstext”。向 dbMemo 添加文本后,“applyupdates”调用现在失败并显示以下消息

column unknown 'fconstext'

尽管有一个使用该名称创建的持久字段。

我不知道这是否有助于或只是使水浑浊。

==== 更多信息,4 月 23 日 ====

我从数据库表中删除了该字段,然后将其添加回来。只要输入到有问题的数据字段中的字符串少于大约 260 个字符,所编写的程序就可以正常工作。我一次添加了十个字符几次都没有问题,直到字符串长度为 256。然后我添加了更多字符(不计算),尝试保存 - 并得到了错误。从这一点开始,尝试再添加一个字符会导致错误消息(出现在 clientdataset 的“applyupdates”方法中)。

最初,该字段包含 832 个字符,因此我可以成功存储的字符数没有硬性限制。但是一旦出现错误信息,它总是出现,好像数据库记得有错误一样。

==== 更多信息,4 月 24 日 ====

再一次,我从数据库中删除了该字段,然后将其添加回来;字符集是 WIN1251,原因我现在还不清楚(我不需要西里尔字符)。无论字段本身是如何定义的,我可以使用数据感知控件输入的最大字符数似乎约为 280。

此后,我开始在发生此问题的实际程序中使用非数据感知控件,并且我可以向您保证,那里不存在此限制。因此,我相当确定问题不是由于字符大小不匹配造成的,正如所建议的那样。不要忘记我使用的是 Delphi 7,它没有 unicode 字符串。我认为其中一个组件存在错误,但由于我使用的是旧版本,我想问题已经解决,但不是在我使用的版本中。

==== 希望最终编辑,25/04/12 ====

按照蚊子的建议,我创建了一个默认字符集为 WIN1252 的新数据库(UTF-8 没有作为选项出现,而且无论如何我的程序不是 unicode)。在这个干净的数据库中,我定义了一个表,其中“constext”字符串的字符集也被定义为 WIN1252。我运行了有问题表单的数据感知版本,并且能够毫无问题地输入文本(目前超过 1700 个字符)。

因此,问题似乎是由为数据库定义一个字符集和为字段定义一个字符集造成的。我不知道如何回顾数据库的默认字符集被定义为什么,所以我无法确认这一点。

我现在有定义一个新数据库(有 50 多个表)并从原始数据库复制数据的小问题。由于这个数据库是为客户的旗舰产品服务的,所以我对这样做有些谨慎......

4

2 回答 2

2

检查UpdateMode提供者的财产。如果它设置为upWhereChanged或者upWhereKeyOnly您需要数据库表中的一个键才能正常工作。

于 2012-04-12T12:36:34.970 回答
1

找不到记录。未指定密钥。

从 id = :p1 的尺度中设置选择 id、name、byteken、timeflag

从 id = 245 的尺度中选择 id、name、byteken、timeflag

设计时的现有 id。


to casts cast (consttext as varchar (2048))..... 如果更改列的定义,则该列类型的现有 CAST 可能会变得无效

算术异常、数值溢出或字符串截断

  1. 字符串截断 当连接的字符串不适合底层 CHAR 或 VARCHAR 数据类型大小时会发生这种情况。如果结果进入表列,则可能是一个有效错误。或者,也许您真的需要增加列大小。类似的情况也适用于存储在存储过程或触发器变量中的中间值

  2. 字符转写失败 当您将数据库中的数据存储在一个字符集中,但转写为所需字符集失败时,会发生这种情况。字符集音译发生的地方有很多。有一个自动的:您从数据库中检索的每条数据(通过 SELECT 或其他方式)都从数据库表列的字符集音译为连接字符集。如果字符集差异太大,将有两种翻译:首先从列字符集到 Unicode,然后从 Unicode 到连接字符集。此外,您可以通过将列转换为另一个字符集来手动请求音译,例如:CAST(column_name AS varchar(100) character set WIN1251)。 原因音译可能失败的原因是某些字符集中不存在某些字符。例如,WIN1252 不包含任何西里尔字符,因此如果您使用连接字符集 WIN1252 并尝试从带有西里尔字符的列中选择,您可能会收到此类错误。在现代,最好在您的应用程序中使用 Unicode 或 UTF8 以及 UTF8 连接字符。并确保您至少使用Firebird 2.0,支持 UTF8。

  3. 使用 DotNetFirebird 时的参数顺序错误 使用 DotNetFirebird 时 将参数添加到 FbCommand 的顺序可能会导致 -303 异常,并提示“算术异常、数字溢出或字符串截断”。参数的顺序必须符合存储过程中参数的顺序 - 否则将引发异常。示例(.NET、C#、DotNetFirebird(使用 FirebirdSql.Data.FirebirdClient;))

    FbCommand CMD = new FbCommand("TBLTEXT_ADDTEXT", cnn); CMD.Parameters.Add("TEXT1", FbDbType.VarChar, 600).Value = strText1; CMD.Parameters.Add("TEXT2", FbDbType.VarChar, 600).Value = strText2; CMD.CommandType = CommandType.StoredProcedure; CMD.ExecuteNonQuery(); 如果“TBLTEXT_ADDTEXT”过程中的参数顺序与您将参数添加到 FbCommand-Object 的顺序不同,您将收到 -303 错误。

4.

No'am Newman 说但是一旦出现错误信息,它总是出现,好像数据库记得有错误一样。

不记得了;数据库损坏了!!!


只要您无法更改数据库字符集并且总是尝试在损坏的表中删除和添加字段,就很难解决问题。1. 对于每个新测试,必须创建一个新数据库(提示:创建一个并复制 x 次)。2. 以纯文本设置的字段,而不是原始字段中存储的西里尔字符;你看不到它们,但它们就在那里。3.设置varchar(8191)和数据库PAGE_SIZE为8192。实际使用UTF8的VARCHAR最大长度为8191

创建数据库语句:

CREATE DATABASE localhost:mybase
  USER SYSDBA
  PASSWORD masterkey
  PAGE_SIZE 8192
  DEFAULT CHARACTER SET UTF8;
  SET NAMES ISO8859_1;

CREATE TABLE scales (
  ID ...,      
  byteken VARCHAR(8191) COLLATE DE_DE,
  ....

排序规则

没有默认排序规则。因此,您应该为要用于排序 (ORDER BY) 或比较 (UPPER) 的每个字段定义一个排序规则:

您还可以使用 ORDER BY 子句指定排序规则:

ORDER BY LASTNAME COLLATE FR_CA, FIRSTNAME COLLATE FR_CA

或使用 WHERE 子句:

WHERE LASTNAME COLLATE FR_CA = :lastnametosearch

统一码

火鸟 2.0。以上。现在有了新的 UTF8 字符集,可以正确处理 UTF-8 格式的 Unicode 字符串。Unicode 排序算法已经实现,所以现在您可以使用 UPPER() 和新的 LOWER() 函数,而无需指定排序规则。

于 2012-04-22T08:31:04.177 回答