0

首先让我说我根本无法修改数据库模式。

我无权访问与数据库交互的任何现有代码。它是一个已编译的程序集,我无法反编译。

在此处输入图像描述

我有一个数据库表,其值在代码中逻辑上用作主键,但不会自动递增。

现在这里是转折点,有时键增加正数,有时增加负数。:(

找不到任何hilo代码的证据。

除了执行 SELECT TOP 1 之外,我不知道如何处理这个问题,添加一个值并希望不会发生重叠。

4

3 回答 3

2

如果您的表是数据库容器 (*.DBC) 的一部分而不是空闲表,那么您可能会找到自动递增数据库容器中的键的代码。

如果您打开表并使用 MODIFY STRUCTURE 命令,您可以在第三个选项卡上看到表的属性。如果表是数据库容器的成员,则将显示数据库的名称以及任何规则,包括触发器和记录规则,这些规则在每次写入表时执行。

在添加自动递增字段之前的日子里,我通过添加如下记录规则来实现自动递增字段:

PROCEDURE TABLE_RR
    LOCAL nOldArea,nUnique

    IF PK=0     &&Only update primary key field when not already set   
        STORE SELECT() TO nOldArea

        &&Open table again in another work area, we can't move the record pointer in a Rule
        IF !USED("TABLE_RR")
            USE TABLE.DBF IN 0 NOUPDATE AGAIN ALIAS TABLE_RR
        ENDIF

        &&Find current maximum value of primary key field, add 1 as next primary key field
        SELECT TABLE_RR
        SET ORDER TO PKTable
        GO BOTT
        STORE 1+PK TO nUnique

        &&Update primary key field for our record
        SELECT(nOldArea)
        REPLACE PK WITH nUnique

     ENDIF

     &&Record rule must return true or changes are rejected
     RETURN .T.

ENDPROC

将此类规则存储在数据库容器存储过程代码区是正常的习惯和做法,但是,只要正在运行的应用程序能够找到该函数,它就会执行。显然,上面的代码示例假定表名为 TABLE,有一个名为 PK 的数字(最好是 Int)字段,索引标记为 PKTable。

因为代码在记录规则中,所以它在任何更新期间都会在记录上执行,因此在记录被锁定时,不会发生冲突。PK 中没有值的任何记录都会得到 1 + 该字段的当前最高值。记录规则旨在验证记录并拒绝无效值,并且必须返回 true (.T.) 才能接受写入。过程中可能会出现其他代码,包括将当前值设置为时间戳字段等。

记录规则可以通过 ALTER TABLE 命令应用于表:

ALTER TABLE 'TABLENAME' SET CHECK PROCEDURENAME()

或通过 MODIFY STRUCTURE 的交互式表格编辑器

于 2013-06-19T17:13:37.157 回答
0

尽管史蒂夫的解决方案非常好,尤其是利用数据库容器和分配规则,但您显然(有点)陷入困境。如果您尝试添加记录并需要创建自己的自动增量,您可能必须通过过程调用并分配它来完成。这只是一个示例,但可能会对您有所帮助。

FUNCTION AddMyNewRecord()
   */ localized variable so you don't accidentally mangle some otherwise 
   */ coincidental variable somewhere else.  Preserve work area at start
   local lnSelect, llSaveOk, lnAttempts, lnNewPKID
   lnSelect = select()
   llSaveOk = .f.    

   select YourAddressTable
   if NOT FLOCK()
      lnAttempts = 0
      do while lnAttempts < 10 AND NOT FLOCK()
         wait window "Attempting lock for address table..." timeout 1
      enddo
   endif 

   if NOT FLOCK()
      messagebox( "Unable to lock file to add next record primary key." )
   else
      */ We have a lock, now try to detect both the highest and lowest
      */ EXISTING key for the table
      use in select( "C_TryNextKey" )
      select MIN( YAT.PK ) as MinKey,;
             MAX( YAT.PK ) as MaxKey ;
         from ;
            YourAddressTable YAT;
         into ;
            cursor C_TryNextKey readwrite 

      */ Determine if you need higher or lower key sequence
      if CriteriaForPositiveKey
         lnNewPKID = C_TryNextKey.MaxKey +1
      else
         */ must be getting next LOWER sequence
         lnNewPKID = C_TryNextKey.MinKey -1
      endif 

      */ close temp cursor from getting respective high / low key
      use in select( "C_TryNextKey" )

      */ NOW, we can add the new record
      Select YourAddressTable
      APPEND BLANK
      */ replace PK and all the other fields you need to do too
      Replace PK with lnNewPKID,;
              Address1 with lcSomeVariableYouHaveForAddress1,;
              Address2 with lcSomeVariableForAddress2,;
              AnyOtherFields with lcOtherFieldsToBeSet

      */ Unlock the address table
      UNLOCK

      */ set flag so we know it worked vs not.
      llSaveOk = .t.
   endif  

   */ Return back where it started
   select( lnSelect )

   */ Return if the save was ok or not.
   return llSaveOk
endproc 

这不会修改现有的数据库,也不会修改表结构。但是,它会在插入新记录内容之前尝试锁定表。然后查看最低和最高 ID。您将不得不分析数据以找出为什么有些人有负面与正面,并更新我在上面代码中的“占位符”放置的条件。最后,解锁桌子。

如果这是有道理的,那就太好了,如果您需要调整,请告诉我,我会尽力为您提供更多指导。

于 2013-06-19T18:27:57.563 回答
0

不知道你需要什么,但是如果你需要额外的PK,你可以使用记录号:

SELECT RECNO() FROM table1
于 2013-06-19T16:17:16.930 回答