从insert语句返回(self)生成的值(没有id,没有返回)

时间:2013-12-08 23:30:16

标签: java sql sql-server db2 ibm-midrange

抱歉,如果题目标题具有误导性或不够准确,但我没有看到如何用一句话来提问。

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

现在我想使用java.sql在表中插入一个新行,并向用户显示插入行的PK。由于默认情况下不生成PK(例如,没有PK的插入值不起作用,在给定的环境中不能使用generated_keys)我已经看到了两种不同的方法:

在两个不同的语句中,首先找到一个可能的下一个键,然后尝试插入(并期望另一个事务在两个语句之间的时间内使用相同的键) - 重试是否有效直到成功或者是否有任何sql技巧使用transaction-settings / locks有帮助吗?我怎么能在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是MSSQL 2008,生产系统目前是AS / 400上的DB2(不知道哪个版本),因此我必须接近SQL标准。我无法以任何方式更改数据库结构(例如,使用生成的密钥,我不确定存储过程)。

1 个答案:

答案 0 :(得分:0)

DB2 for i允许生成的密钥,存储过程,用户定义的函数 - 几乎所有SQL Server都可以做的事情。确切的实现是不同的,但这是手册的用途:-)询问您的管理员他们正在运行的IBM i版本,然后点击Infocenter了解详细信息。

约束因素是您无法改变数据库设计;在现有密钥空间中回填“漏洞”的同时,你很难看到多个进程试图插入。这是一个非常难以破解的坚果。因为您无法更改数据库设计,除了允许和处理PK冲突之外,没有什么可以做的。没有SQL技巧可以帮助 - SQL方法是让数据库生成PK,而不是应用程序。

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

  1. 创建一个UDF,所有INSERT客户端都使用该UDF来检索下一个可用的PK。使用“可用数字”表并在发布时将其删除。
  2. 预先插入所有可用的号码。强制客户端进行更新。使它们成为FETCH ... FOR UPDATE where(其余数据=未填充)。这将锁定行,避免冲突,并使PK立即可用。
  3. 使用此表原样保留数据库和其他应用程序,但让您的INSERT进程从一块已经预留给您使用的密钥块中抽取。将下一个可用编号保留在SQL SEQUENCE或IBM i数据区中。这只适用于键空间中有一个非常大的洞,但尚未使用。