从insert语句返回(自己)生成的值(无id,不返回)



对不起,如果问题标题有误导性或不够准确,但我不知道如何在一句话中提问。

假设我们有一个表,其中PK是一个字符串(从"100000"到"999999"的数字,逗号仅用于可读性)。也可以说,PK不是按顺序使用的。

现在,我想使用java.sql在表中插入一个新行,并向User显示插入行的PK。由于PK不是默认生成的(例如,没有PK的插入值不起作用,generated_keys之类的东西在给定的环境中不可用),我看到了两种不同的方法:

在两个不同的语句中,首先找到一个可能的下一个键,然后尝试插入(并期望在两个语句之间的时间内另一个事务使用相同的键)-重试直到成功是有效的,还是任何带有事务设置/锁的sql技巧都有帮助?我如何在java.sql中实现这一点?

对我来说,这是一个令人失望的解决方案,因为它的不确定性行为(也许你可以说服我相反),所以我寻找了另一个:

插入一个嵌套的select语句,该语句可以查找下一个可能的PK。在自己生成PK时查找其他答案,我几乎找到了该语句的有效解决方案(省略了从字符串到int的强制转换):

INSERT INTO mytable (pk,othercolumns)
VALUES(
(SELECT MIN(empty_numbers.empty_number) 
  FROM (SELECT t1.pk + 1 as empty_number 
    FROM mytable t1
    LEFT OUTER JOIN mytable t2
    ON t1.pk + 1  = t2.pk
    WHERE t2.pk IS NULL
    AND t1.pk > 100000)
  as empty_numbers),
 othervalues);

这就像一个魅力,并且(afaik)有一个比我的第一种方法更可预测和稳定的解决方案,但是:我怎么可能从该语句中检索生成的PK?我读到没有办法直接返回插入的行(或任何列),我发现的大多数谷歌结果都指向返回生成的键——即使我的键是生成的,它也不是由DBMS直接生成的,而是由我的语句生成的。

注意,开发中使用的DBMS是MSSQL2008,生产系统目前是AS/400上的DB2(不知道是哪个版本),所以我必须坚持SQL标准。我不能以任何方式更改数据库结构(例如,使用生成的密钥,我不确定存储过程)。

DB2fori允许生成密钥、存储过程、用户定义函数-几乎所有SQL Server可以做的事情。具体的实现方式不同,但这就是手册的用途:-)询问管理员他们运行的是什么版本的IBMi,然后访问信息中心了解详细信息。

约束因素是不能更改数据库设计;当在现有密钥空间中回填"孔"时,您显然遇到了多个进程试图INSERT的问题。这是一个很难解决的问题。因为您无法更改DB设计,所以除了允许和处理PK冲突之外,没有什么可做的。SQL技巧没有任何帮助——SQL方法是让DB生成PK,而不是应用程序。

如果允许某些更改,则有几种替代方案可供建议。所有这些都有需要解决的问题,但由于应用程序设计的原因,这在目前是不可避免的。

  1. 创建一个所有INSERT客户端用来检索下一个可用PK的UDF。使用一个"可用数字"表,并在发布时删除它们
  2. 预先插入所有可用的号码。强制客户端执行UPDATE。让他们FETCH。。。FOR UPDATE where(其余数据=未填充)。这将锁定行,避免冲突,并使PK立即可用
  3. 让DB和其他应用程序按原样使用此表,但让INSERT进程从为您留出的一组键中提取。将下一个可用数字保留在SQL SEQUENCE或IBM i数据区域中。只有当键空间中有一个尚未使用的非常大的孔时,这才有效

相关内容

  • 没有找到相关文章

最新更新