【问题标题】:dbExpress/No key specifieddbExpress/未指定密钥
【发布时间】:2012-04-12 10:49:02
【问题描述】:

我正在使用 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 上找到了 this question,这似乎解决了类似的问题。我将查询更改为

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 多个表)并从原始数据库中复制数据。由于这个数据库是为客户的旗舰产品服务的,所以我对这样做有点谨慎......

【问题讨论】:

  • 这不会与this 有某种关系吗?您是否在 Delphi 7 上安装了更新?
  • @TLama:我很确定我确实上传了很长时间的修复。有问题的表格对我来说使用什么是样板代码 - 它几乎可以在我的程序中的其他任何地方使用。在代码不起作用的极少数情况下,我使用了非数据感知控件,它始终可以解决问题——但这需要更多的编程。我想找出有时我的样板代码不起作用的原因。
  • 尝试为TSQLDataSet 中的ID 字段设置pfInKey。还要确保如果您使用持久字段,则需要添加新的varchar 字段。
  • @kobik:我尝试了上述两个建议。通常,我不会在这种表单上使用持久字段,但我尝试添加它们(并设置 maxlength 属性)无济于事。
  • 你在TSQLDataSetTClientDataSet上试过了吗?

标签: delphi delphi-7 firebird dbexpress


【解决方案1】:

检查提供程序的UpdateMode 属性。如果设置为upWhereChangedupWhereKeyOnly,则需要数据库表中的键才能正常工作。

【讨论】:

  • (a) 提供者的更新模式是 upWhereAll。 (b) 只要新文本字段不存在,数据就会更新。 (c) 数据库表有键,而且肯定存在。
  • 抱歉,我不熟悉在 Delphi 7 下运行的 Firebird 的任何 dbx 驱动程序。您可以尝试将 UpdateMode 更改为其他两个选项之一。
  • 我更改了更新模式,但没有任何区别。我不认为这是问题所在。
【解决方案2】:

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

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

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

设计时的现有 id。


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

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

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

  2. 字符音译失败 当您将数据库中的数据存储在一个字符集中时,会​​发生这种情况,但音译为所需字符集失败。字符集音译发生的地方有很多。有一个自动的: 您从数据库中检索到的每条数据(通过 SELECT 或其他方式)都从数据库字符集表的列音译为连接字符集。如果字符集差异太大,将有两种翻译:首先从列字符集到 Unicode,然后从 Unicode 到连接字符集。 此外,您可以通过将列转换为另一个字符集来手动请求音译,例如: CAST(column_name AS varchar(100) 字符集 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 said 但是一旦出现错误信息,它总是会出现,好像 数据库记得有错误。

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


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

CREATE DATABASE 语句:

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

Unicode

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

【讨论】:

  • 即使我将参数作为字符串文字传递,如上所述,我仍然会收到“EDatabase 错误:算术异常、数字溢出或字符串截断”错误消息。
  • 参考您的扩展答案:1)我已经删除了演员表,没有区别。 2) 字段定义长度为2048,记录当前包含832个字符,所以没有字符串溢出。 3) 我用不同的字符集向表中添加了一个新字段 - 当我尝试访问该字段时,我收到一条关于无法音译内容的错误消息。由于我没有收到带有给定字段的消息,因此这不是问题。 4)由于只有一个参数,所以几乎不可能顺序错误。
  • 客户端数据库设置为 UTF8,服务器也设置为 UTF8。使用 charset=UTF8; 创建一个新数据库;
  • @No'am Newman:只要您无法更改数据库字符集并且总是尝试在损坏的表中删除和添加字段,就很难解决问题。 1. 对于每个新测试,都必须创建一个新数据库。 2. 以纯文本设置的字段,而不是原始字段中存储的西里尔字符;你看不到它们,但它们就在那里。 3.设置varchar(8192)和数据库页面大小为8192。
  • 查看我对问题的修订,日期为 25/04/12。
猜你喜欢
  • 2017-04-30
  • 1970-01-01
  • 1970-01-01
  • 2017-12-04
  • 2019-11-22
  • 2018-07-01
  • 2021-10-24
  • 2021-04-11
相关资源
最近更新 更多