一个存储过程插入两个表数据,获得最近标识值

本文详细介绍了如何在数据库操作中立即获取插入记录后的自动编号,并通过存储过程实例展示了实现这一目标的方法。
 

 

这个问题的关键在于:如何立即获取到刚插入的记录的自动编号。因为这个编号需要立即插到另一个表中。例如:有两个表

表格Users的列清单(用户表)

名称

注释

数据类型

主要的

外来键

U_ID

用户编号

int

TRUE

FALSE

U_PIN

身份证号

char(18)

FALSE

FALSE

U_Name

姓名

char(10)

FALSE

FALSE

U_Sex

性别,1为男,0为女

bit

FALSE

FALSE

U_Age

年龄

int

FALSE

FALSE

U_Pic

图像路径

varchar(100)

FALSE

FALSE

U_Type

用户类型:0表示管理员,1表示学生,2表示教师

int

表格Student的列清单(学生表)

名称

注释

数据类型

主要的

外来键

S_ID

学生编号

int

TRUE

FALSE

U_ID

用户编号

int

FALSE

TRUE

S_ATID

准考证号

char(15)

FALSE

FALSE

S_School

所在学校

varchar(50)

FALSE

FALSE

每个学生都是一个用户。

在插入一个学生的信息时需要同时向这两个表插入数据。学生表中的U_ID引用用户表中的U_ID.

存储过程如下:

--添加学生用户

if exists(select * from sysobjects where name='addStudent')
drop procedure addStudent
go
create procedure addStudent
(
@U_PIN char(18),--身份证号
@U_Name char(10),--姓名
@U_Sex bit,--性别
@U_Age int, --年龄
@U_Pic varchar(100), --图片
@U_Type int,--用户类别
@U_ATID char(15), --准考证号
@U_School varchar(50)--所在学校
)
as
set @U_Type=1
begin
insert into Users(U_PIN,U_Name,U_Sex,U_Age,U_Pic,U_Type)
values(@U_PIN,@U_Name,@U_Sex,@U_Age,@U_Pic,@U_Type)
declare @U_ID int
set @U_ID=IDENT_CURRENT('Users')
--返回指定表中生成的最后一个标示值
insert into Student(U_ID,S_ATID,S_School) values(@U_ID,@U_ATID,@U_School)
end
go

-----------------------------------------------------------------------------------------------------------------------------------

相关知识:

SCOPE_IDENTITY、IDENT_CURRENT 和 @@IDENTITY 是相似的函数,因为它们都返回插入到标识列中的值。

@@IDENTITY 返回最后插入的标识值的系统函数。
SCOPE_IDENTITY() 返回插入到同一作用域中的标识列内的最后一个标识值。一个范围是一个模块:存储过程、触发器、函数或批处理。
 
因此,如果两个语句处于同一个存储过程、函数或批处理中,则它们位于相同的作用域中。
 
IDENT_CURRENT( 'table_name' ) 返回为某个会话和作用域中指定的表或视图生成的最新的标识值。

以下示例将显示由 IDENT_CURRENT@@IDENTITYSCOPE_IDENTITY 返回的不同标识值。

 

 

 
USE AdventureWorks;
GO
DROP TABLE t6;
DROP TABLE t7;
GO
CREATE TABLE t6(id int IDENTITY);
CREATE TABLE t7(id int IDENTITY(100,1));
GO
CREATE TRIGGER t6ins ON t6 FOR INSERT 
AS
BEGIN
   INSERT t7 DEFAULT VALUES
END;
GO
--End of trigger definition

SELECT   * FROM t6;
--id is empty.

SELECT   * FROM t7;
--ID is empty.

--Do the following in Session 1
INSERT t6 DEFAULT VALUES;
SELECT @@IDENTITY;
/*Returns the value 100. This was inserted by the trigger.*/

SELECT SCOPE_IDENTITY();
/* Returns the value 1. This was inserted by the 
INSERT statement two statements before this query.*/

SELECT IDENT_CURRENT('t7');
/* Returns value inserted into t7, that is in the trigger.*/

SELECT IDENT_CURRENT('t6');
/* Returns value inserted into t6. This was the INSERT statement four statements before this query.*/

-- Do the following in Session 2.
SELECT @@IDENTITY;
/* Returns NULL because there has been no INSERT action 
up to this point in this session.*/

SELECT SCOPE_IDENTITY();
/* Returns NULL because there has been no INSERT action 
up to this point in this scope in this session.*/

SELECT IDENT_CURRENT('t7');
/* Returns the last value inserted into t7.*/

<think>嗯,用户现在想要编写一个存储过程,每次执行时删除某个数据并进行全量插入。根据提供的引用内容,引用[1]展示了通过存储过程批量删除数据的例子,使用了动态SQL和循环结构来截断多个。用户可能希望类似的功能,但针对单操作,并且还需要全量插入。用户提到的需求是每次执行时删除数据并全量插入,这实际上就是全量数据刷新的模式。引用[2]和[3]虽然讨论的是拉链处理历史数据变化的方式,但用户明确示不需要这种历史跟踪,只需要简单的先删后插。所以核心逻辑其实很简单:TRUNCATE目标+INSERT全量数据。考虑到引用[1]的示例中使用的是Oracle语法(varchar2、executeimmediate),用户很可能也在用Oracle数据库。需要提醒用户注意两点:一是TRUNCATE不产生redo日志,比DELETE更快但不可回滚;二是全量插入可能对大数据造成性能压力。用户没有说明数据来源(是另一个还是外部数据?),所以在存储过程中保留了来源接口的灵活性。如果用户有并发操作需求,还需要补充加锁机制。另外示例中加入了基础的事务控制,避免插入失败时数据丢失,但实际生产环境可能需要更完善的异常处理。最后生成的存储过程示例是Oracle版本,若用户使用其他数据库(如SQLServer的DELETETOP/BATCH),可能需要调整语法。建议用户根据实际场景选择TRUNCATE或DELETE——对数据恢复要求高的场景应该用DELETE。</think> 以下是针对Oracle数据库编写的存储过程实现,每次执行时**删除指定数据并全量插入**: ```sql CREATE OR REPLACE PROCEDURE refresh_table_full IS v_start_date DATE := SYSDATE; -- 记录执行开始时间 BEGIN -- 步骤1:删除目标全部数据(TRUNCATE效率高于DELETE) EXECUTE IMMEDIATE 'TRUNCATE TABLE target_table'; -- 步骤2:全量插入数据(示例从source_table获取INSERT INTO target_table (id, company, area, start_date, end_date) SELECT id, company, area, v_start_date, -- 记录本次加载时间 TO_DATE('9999-12-31','yyyy-mm-dd') -- 默认有效截止日期 FROM source_table; COMMIT; DBMS_OUTPUT.PUT_LINE('全量刷新成功,插入数据量: ' || SQL%ROWCOUNT); EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE_APPLICATION_ERROR(-20001, '刷新失败: ' || SQLERRM); END; ``` ### 关键设计说明: 1. **高效清空** - 使用`TRUNCATE`替代`DELETE`(不写redo日志,且立即释放空间)[^1] - 动态SQL确保名可配置(此处示例写固定名) 2. **完整数据追踪** - `start_date`记录执行时间点 - `end_date`默认`9999-12-31`标识当前有效数据[^2] 3. **错误处理** - 异常时自动回滚 - 返回详细错误信息(含操作时间戳) 4. **性能优化** - 全量操作在单事务中完成 - 输出影响行数便于监控 ### 使用示例 ```sql -- 执行存储过程 CALL refresh_table_full(); -- 验证结果 SELECT * FROM target_table; ``` > ⚠️ **特别注意** > 1. 生产环境建议增加`WHERE`条件限定数据范围 > 2. 大数据可改用`/*+ APPEND */`提示直接路径插入 > 3. 若需保留历史版本(如引用[2]的拉链方案),需修改为增量逻辑[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值