注册 登录
编程论坛 VFP论坛

请教如何查询SQL SERVER增加记录的ID值

fanjinyu9108 发布于 2024-05-25 11:14, 578 次点击
我使用SPT的方式在SQL SERVER表A中增加一条记录,还没有保存,现在在保存这条记录之前,我需要获得这条新增记录的ID值,然后在另外一个表B中增加多条记录,这些多条记录关联着前面获取的ID值,将后面表B的某个字段值更新为获取的ID值后,然后一起保存。请问如何获取ID值,(程序是在多用户情况下使用的,所以选择在保存记录前获取ID值)
12 回复
#2
fanjinyu91082024-05-25 16:44
关于这个问题,我想做个补充说明,在SQL SERVER里面,A表和B表是一对多的关系,如果表在本地,我可以先增加A表的记录并存盘,提取出A表的ID值,再增加B表的记录,并且把ID值存到B表的字段里面,但是现在是远程网络数据,我必须保证A表的数据和B表的数据要么同时存盘,要么同时回滚(rollback)取消,否则可能出现A表存盘,网络突然中断,B表却没有存盘的情况
#3
fanjinyu91082024-05-25 17:08
在SQL Server中,如果想要外键(FK)自动填充,可以在创建或修改表时指定某个列为外键,并设置其为IDENTITY属性。但是,需要注意的是,外键列通常不能直接设置为IDENTITY类型,因为它需要参照另一个表的主键。

如果你想要外键自动填充,通常是指当你插入新行到包含外键的表时,外键列会自动填充为另一个表的相应主键值。这通常通过触发器实现。

以下是一个示例,展示了如何创建一个触发器来在插入新行时自动填充外键:

-- 假设有两个表:Order (主表) 和 OrderDetail (子表)
-- Order 表有一个名为 OrderID 的主键
-- OrderDetail 表有一个名为 OrderID 的外键,需要自动填充
 
-- 创建触发器来在插入OrderDetail新行时自动填充OrderID
CREATE TRIGGER trg_OrderDetail_Insert
ON OrderDetail
AFTER INSERT
AS
BEGIN
  SET NOCOUNT ON;
  UPDATE OrderDetail
  SET OrderID = i.OrderID
  FROM Inserted i
  WHERE OrderDetail.DetailID = i.DetailID; -- 假设DetailID是OrderDetail的主键
END;
 
-- 插入新行到OrderDetail时,只需要指定DetailID和其他相关列,OrderID将自动填充
-- 例如:
INSERT INTO OrderDetail (DetailID, ProductID, Quantity)
VALUES (1, 101, 2);
在这个例子中,OrderDetail表的OrderID列需要在插入新行时自动填充为Order表中对应的OrderID。触发器trg_OrderDetail_Insert会在每次插入操作之后执行,并自动更新OrderDetail表中的OrderID列。

请注意,这只是一个简化的示例,实际使用时需要根据你的数据库结构和需求进行相应的调整。
#4
fanjinyu91082024-05-25 17:09
以上是我在网上搜索自动填充,我这种情况可以实现自动填充吗?

#5
kangss2024-05-25 19:54
以下是引用fanjinyu9108在2024-5-25 16:44:46的发言:

关于这个问题,我想做个补充说明,在SQL SERVER里面,A表和B表是一对多的关系,如果表在本地,我可以先增加A表的记录并存盘,提取出A表的ID值,再增加B表的记录,并且把ID值存到B表的字段里面,但是现在是远程网络数据,我必须保证A表的数据和B表的数据要么同时存盘,要么同时回滚(rollback)取消,否则可能出现A表存盘,网络突然中断,B表却没有存盘的情况

开启SQL事务,执行你需要执行的命令,A、B表都处理完之后,提交事务确认。在提交事务确认之前,如果出现异常,你执行回滚命令,2个表是同时回滚的。这是SQL的机制,不需要你控制。
#6
fanjinyu91082024-05-26 09:24
程序代码:
SQLSetprop(nhandle,'Transactions',2)        && 开启远程手工事务
    BEGIN TRANSACTION
   
     
    select c_t  &&表1
    a1=TABLEUPDATE(.t.)
    **Ac3=SQLEXEC(nhandle,"SELECT SCOPE_IDENTITY() AS NewID ","c_id")  &&  现在连接处于打开状态
    Ac3=SQLEXEC(nhandle,"SELECT MAX(id) AS NewID from yksb.dbo.shebei_zl","c_id")  &&  现在连接处于打开状态
     IF  Ac3<0
       END TRANSACTION  
       = SQLDISCONNECT(nhandle)
       MESSAGEBOX("读取数据错误!",0,"错误信息")
       RETURN TO MASTER
     ENDIF
     SELECT c_id
     myid=NewID
     UPDATE c_t2 SET id_zl=myid  &&直接修改中间表
   
   
    select c_t2   &&表2
    a2=TABLEUPDATE(.t.)
    IF a1=.t. AND a2=.t.
     END TRANSACTION  
    ELSE
        rollback  
        *END TRANSACTION
    ENDIF
    SQLSetprop(nhandle,'Transactions',1)        && 开启远程自动事务
    = SQLDISCONNECT(nhandle) &&关闭
    IF a1=.t. AND a2=.t.
      IF  弹出对话=.t.
       MESSAGEBOX("数据保存成功!",0,"信息")
     endif  
    ELSE
       MESSAGEBOX("数据保存失败!",0,"信息")
       弹出对话=.t.
       RETURN TO master
    endif



[此贴子已经被作者于2024-5-26 10:15编辑过]

#7
fanjinyu91082024-05-26 09:29
以上是我的代码,我取表A的id值是用“SELECT MAX(id) AS NewID from yksb.dbo.shebei_zl“的语句,这样的方法在多用户状态下会不会取错值,把别人存盘的ID值取回?
#8
fanjinyu91082024-05-26 09:53
请师傅们帮忙看看

[此贴子已经被作者于2024-5-26 10:16编辑过]

#9
kangss2024-05-26 12:54
以下是引用fanjinyu9108在2024-5-26 09:29:23的发言:

以上是我的代码,我取表A的id值是用“SELECT MAX(id) AS NewID from yksb.dbo.shebei_zl“的语句,这样的方法在多用户状态下会不会取错值,把别人存盘的ID值取回?

开启事务时,你操作的表是自动加锁的,别人取不到ID值。
你可以在事务执行中间增加messagebox让程序暂停,在另外一台电脑上或者另外一个VFP9里面去读取ID,试试就明白了
#10
fanjinyu91082024-05-26 14:21
谢谢师傅们的解答,我还有一个疑问,就是表A存盘后,在准备操作表B的时候,突然断网了,这时就存在表A存盘了,表B却没有存盘,有这种可能吗?能避免这种情况吗?
#11
laowan0012024-05-26 18:45
楼主那种分次执行SQL语句的做法(SQLEXEC(nhandle,SQL语句),理论上是存在数据保存不完整的情况
介绍一下我的做法
把需要执行的SQL语句用text to 变量...endtext做成一个文本
象下面这样:
text to 变量名
    BEGIN TRANSACTION
    需要执行的SQL语句
    ...
    commit TRANSACTION
endtext
SQLEXEC(nhandle,变量名)
这样可一次执行全部语句,使用事务可以保证SQL完整执行,如果出现中断或异常,语句不会真正提交,也不需要你自己处理回滚

#12
yiyanxiyin2024-05-27 10:28
你得使用with(updlock)使用全表的读写锁,这样写: SELECT MAX(id) AS NewID from yksb.dbo.shebei_zl with(updlock),    并将代码放入tran中, 这样才能独占并阻止其他线程读取表, 这样带来的问题就是非常影响性能

所以改一个方案:    建一个guid字段,  因为guid是唯一的, 不会产生相同值,在程序中生成guid, 插入记录后, 通过这个guid字段去反查出id, 这样可以不用加锁
#13
fanjinyu91082024-06-02 19:14
非常给那些师傅们的解答,问题还没有彻底解决,laowan001和yiyanxiyin2位版主的解答我还暂时没有弄通,暂时先放放,过一段时间在来请教,再次感谢
1