关于sqlserver临时表的问题,请教高手!

sonnchuui520 2013-08-12 01:41:33
现在在做一个项目,用到的功能是这样的!
每个表都有触发器,在更新,追加的时候,会给记录的登陆用户,登陆机器名这两个字段设定值!这两个值是在触发器中从本地临时表中取到的!
而临时表是在应用程序中创建的,因为sqlserver的本地临时表是根据会话来的,会话结束了,这个临时表就被删除掉了,所以在应用程序中,使用ExcuteNoQuery()创建临时表时(在存储过程中创建也一样 执行EXEC后会话结束),会话就结束了,临时表就被删除了,
这时更新数据库数据库数据,触发触发器触发时根本找不到之前创建的临时表了,所以不能正确设定登陆用户,登陆机器名了!
如果用全局临时表的话,又怕有并发问题,
有没有高手知道有什么设定或是别的解决办法,请指教啊!
...全文
235 点赞 收藏 23
写回复
23 条回复
sonnchuui520 2013年08月13日
引用 20 楼 wwwwgou 的回复:
[quote=引用 19 楼 sonnchuui520 的回复:] [quote=引用 18 楼 wwwwgou 的回复:]
--SQL SERVER 的临时表达不到postgresql的效果,建议:
--方法1
com.ExecuteNonQuery();	--生成一个guid+机器名+登陆名,三个字段缓存到实体表
object obj = invocation.Proceed();	--把GUID传给这个函数,从上面的实体表中取到相应数据

--方法2
com.ExecuteNonQuery();	--删除这行
object obj = invocation.Proceed(); --把删除的那行代码放在这个里面的SQL中
谢谢啊! 你这两个方法应该都能实现,但是修改的代码量会很大 以你的经验来看 没有其他简单的方法了吗?[/quote] SORRY,想不到了,顶起来,期待大神出现……[/quote] 已经很感谢了!
回复 点赞
sonnchuui520 2013年08月13日
期待大神出现!
回复 点赞
Shawn 2013年08月13日
引用 19 楼 sonnchuui520 的回复:
[quote=引用 18 楼 wwwwgou 的回复:]
--SQL SERVER 的临时表达不到postgresql的效果,建议:
--方法1
com.ExecuteNonQuery();	--生成一个guid+机器名+登陆名,三个字段缓存到实体表
object obj = invocation.Proceed();	--把GUID传给这个函数,从上面的实体表中取到相应数据

--方法2
com.ExecuteNonQuery();	--删除这行
object obj = invocation.Proceed(); --把删除的那行代码放在这个里面的SQL中
谢谢啊! 你这两个方法应该都能实现,但是修改的代码量会很大 以你的经验来看 没有其他简单的方法了吗?[/quote] SORRY,想不到了,顶起来,期待大神出现……
回复 点赞
sonnchuui520 2013年08月13日
引用 18 楼 wwwwgou 的回复:
--SQL SERVER 的临时表达不到postgresql的效果,建议:
--方法1
com.ExecuteNonQuery();	--生成一个guid+机器名+登陆名,三个字段缓存到实体表
object obj = invocation.Proceed();	--把GUID传给这个函数,从上面的实体表中取到相应数据

--方法2
com.ExecuteNonQuery();	--删除这行
object obj = invocation.Proceed(); --把删除的那行代码放在这个里面的SQL中
谢谢啊! 你这两个方法应该都能实现,但是修改的代码量会很大 以你的经验来看 没有其他简单的方法了吗?
回复 点赞
sonnchuui520 2013年08月13日
大神在哪里?
回复 点赞
Shawn 2013年08月12日
--SQL SERVER 的临时表达不到postgresql的效果,建议:
--方法1
com.ExecuteNonQuery();	--生成一个guid+机器名+登陆名,三个字段缓存到实体表
object obj = invocation.Proceed();	--把GUID传给这个函数,从上面的实体表中取到相应数据

--方法2
com.ExecuteNonQuery();	--删除这行
object obj = invocation.Proceed(); --把删除的那行代码放在这个里面的SQL中
回复 点赞
sonnchuui520 2013年08月12日
引用 16 楼 luckyrandom 的回复:
需要改下程序,登录后注册SPID即可
谢谢回答! 能详细点吗?登录后注册SPID?是什么意思?
回复 点赞
Q315054403 2013年08月12日
需要改下程序,登录后注册SPID即可
回复 点赞
sonnchuui520 2013年08月12日
引用 13 楼 wwwwgou 的回复:
[quote=引用 11 楼 sonnchuui520 的回复:] 代码结构大概是这样 string strsql = "select @userid,@userNm into #pro_set"; //这里追加一些参数 com.Parameters.Add(prmFuncName); //执行创建临时表的sql com.ExecuteNonQuery(); //这里调用了一个更新或追加的sql(执行这个sql时会触发触发器 before insert 也是在触发的时候更改要反映到数据库的记录,这时临时表已经看不到了) object obj = invocation.Proceed(); //提交数据库事物 current.Commit();
临时表只在当前作用域可见,所以楼主需要把两步合并为一步,即可[/quote] 恩 合成一步是可以,但是对当前的项目不太适用啊! 当前项目创建临时表是在共通方法中实现的,使用临时表是在触发器中,如果合到一起一是修改的可行性不清楚,二是修改的作业量太大,这是个300来人月的项目。
回复 点赞
sonnchuui520 2013年08月12日
引用 12 楼 wwwwgou 的回复:
[quote=引用 5 楼 sonnchuui520 的回复:] [quote=引用 3 楼 wwwwgou 的回复:] 没用过postgresql数据库。不太明白它的用法。 想问一下,楼主是否这样:先创建一个临时表,然后,往某些表中INSERT或UPDATE,同时要记录这个操作是哪个登陆用户所为。上面这些操作,是在同一个存储过程中?
不在一个存储过程。 这样说吧,首先开启了个数据库事物,然后执行一个sql(sqlserver里只能是存储过程或是PLSQL语句)创建了一个临时表,然后执行另一个往某个表中INSERT或UPDATE的sql语句,这个语句执行时会触发触发器,在触发器里对当前更新或追加的数据做一些修改(就是设定用户名和机器名),然后更新或插入到数据库,然后提交事物。 [/quote] 楼主只需要把创建临时表的SQL和INSERT或UPDATE的SQL语句,放在同一个事务里,即可。参考下面的测试:
USE CSDN
go
--测试数据
CREATE TABLE trigger_test(id INT,SPID INT, name CHAR(8000))	--加个name字段,让插入的2条数据,分别放在2个页面上,防止闩锁对测试的影响
go
--创建触发器
CREATE TRIGGER tr_test1 ON dbo.trigger_test
AFTER INSERT, UPDATE
as
BEGIN
	UPDATE A
	SET a.spid = (SELECT TOP(1) spid FROM #temp)	--请明这里访问的#temp表,只是当前登陆用户的
	from trigger_test A
	INNER JOIN INSERTED B
		ON a.id = b.id
END
go

--第一个连接,分两步执行:
BEGIN TRAN
--#1.创建临时表
IF object_id('tempdb..#temp', 'u') IS NOT NULL
	DROP TABLE #temp
CREATE TABLE #TEMP (SPID INT) 
INSERT #temp(SPID) SELECT @@SPID	--第一步执行到这儿时,停止,再去另外一个连接中的所有SQL。然后再回来,执行完下面的SQL

--#2.执行insert或update语句
INSERT dbo.trigger_test (id, name) VALUES(5, '5')

--#3.触发触发器
COMMIT TRAN


--第二个连接,一下子执行完
USE CSDN
go

BEGIN TRAN
--#1.创建临时表
IF object_id('tempdb..#temp', 'u') IS NOT NULL
	DROP TABLE #temp
CREATE TABLE #TEMP (SPID INT) 
INSERT #temp(SPID) SELECT @@SPID

--#2.执行insert或update语句
INSERT dbo.trigger_test (id, name) VALUES(0, '0')

--#3.触发触发器
COMMIT TRAN

--查看结果
SELECT * FROM trigger_test
/*
id	SPID	name
0	65	0
5	52	5
*/
[/quote] 辛苦了!感谢! 下面是我的一个例子!说明了 一个会话结束 临时表就已经不存在了 这是我目前的问题! -- PROC: set_prc_info(@user_code varchar(12), @term_id varchar(100), @func varchar(50)) -- DROP PROC set_prc_info1 create PROC [dbo].[set_prc_info1](@user_code varchar(12), @term_id varchar(100), @func varchar(50)) AS declare @sql as varchar(100) if Object_id('#prc_env') is null begin set @sql = 'CREATE TABLE #prc_env(userid varchar(12),termid varchar(100),funcid varchar(50));'; --执行这个创建临时表的SQL文,会话已经结束 (这相当于我在应用程序中 用 cmd.ExecuteNoQuery() 执行创建临时表) EXEC(@sql); --执行到这个地方时 这个临时表已经不存在了(这里相当于我的应用程序中执行其它的Insert/Update 语句) insert into #prc_env (userid,termid,funcid) VALUES (@user_code,@term_id,@func); end --测试一下发现 那个临时表已经不存在了 exec [dbo].[set_prc_info1] 'test1','test2','test3'
回复 点赞
Shawn 2013年08月12日
引用 11 楼 sonnchuui520 的回复:
代码结构大概是这样 string strsql = "select @userid,@userNm into #pro_set"; //这里追加一些参数 com.Parameters.Add(prmFuncName); //执行创建临时表的sql com.ExecuteNonQuery(); //这里调用了一个更新或追加的sql(执行这个sql时会触发触发器 before insert 也是在触发的时候更改要反映到数据库的记录,这时临时表已经看不到了) object obj = invocation.Proceed(); //提交数据库事物 current.Commit();
临时表只在当前作用域可见,所以楼主需要把两步合并为一步,即可
回复 点赞
Shawn 2013年08月12日
引用 5 楼 sonnchuui520 的回复:
[quote=引用 3 楼 wwwwgou 的回复:] 没用过postgresql数据库。不太明白它的用法。 想问一下,楼主是否这样:先创建一个临时表,然后,往某些表中INSERT或UPDATE,同时要记录这个操作是哪个登陆用户所为。上面这些操作,是在同一个存储过程中?
不在一个存储过程。 这样说吧,首先开启了个数据库事物,然后执行一个sql(sqlserver里只能是存储过程或是PLSQL语句)创建了一个临时表,然后执行另一个往某个表中INSERT或UPDATE的sql语句,这个语句执行时会触发触发器,在触发器里对当前更新或追加的数据做一些修改(就是设定用户名和机器名),然后更新或插入到数据库,然后提交事物。 [/quote] 楼主只需要把创建临时表的SQL和INSERT或UPDATE的SQL语句,放在同一个事务里,即可。参考下面的测试:
USE CSDN
go
--测试数据
CREATE TABLE trigger_test(id INT,SPID INT, name CHAR(8000))	--加个name字段,让插入的2条数据,分别放在2个页面上,防止闩锁对测试的影响
go
--创建触发器
CREATE TRIGGER tr_test1 ON dbo.trigger_test
AFTER INSERT, UPDATE
as
BEGIN
	UPDATE A
	SET a.spid = (SELECT TOP(1) spid FROM #temp)	--请明这里访问的#temp表,只是当前登陆用户的
	from trigger_test A
	INNER JOIN INSERTED B
		ON a.id = b.id
END
go

--第一个连接,分两步执行:
BEGIN TRAN
--#1.创建临时表
IF object_id('tempdb..#temp', 'u') IS NOT NULL
	DROP TABLE #temp
CREATE TABLE #TEMP (SPID INT) 
INSERT #temp(SPID) SELECT @@SPID	--第一步执行到这儿时,停止,再去另外一个连接中的所有SQL。然后再回来,执行完下面的SQL

--#2.执行insert或update语句
INSERT dbo.trigger_test (id, name) VALUES(5, '5')

--#3.触发触发器
COMMIT TRAN


--第二个连接,一下子执行完
USE CSDN
go

BEGIN TRAN
--#1.创建临时表
IF object_id('tempdb..#temp', 'u') IS NOT NULL
	DROP TABLE #temp
CREATE TABLE #TEMP (SPID INT) 
INSERT #temp(SPID) SELECT @@SPID

--#2.执行insert或update语句
INSERT dbo.trigger_test (id, name) VALUES(0, '0')

--#3.触发触发器
COMMIT TRAN

--查看结果
SELECT * FROM trigger_test
/*
id	SPID	name
0	65	0
5	52	5
*/
回复 点赞
sonnchuui520 2013年08月12日
代码结构大概是这样 string strsql = "select @userid,@userNm into #pro_set"; //这里追加一些参数 com.Parameters.Add(prmFuncName); //执行创建临时表的sql com.ExecuteNonQuery(); //这里调用了一个更新或追加的sql(执行这个sql时会触发触发器 before insert 也是在触发的时候更改要反映到数据库的记录,这时临时表已经看不到了) object obj = invocation.Proceed(); //提交数据库事物 current.Commit();
回复 点赞
sonnchuui520 2013年08月12日
引用 9 楼 dotnetstudio 的回复:
关于用户登录为什么不保存在应用程序的Session中呢
已经保存了,在应用程序中是可以用到的,但是在触发器中是看不到的。 系统原来用的是POSTGRE数据库,这样使用都没问题,这样做主要是节省了开发的过程中每个更新追加的sql文中都去设定这些用户信息。
回复 点赞
KeepSayingNo 2013年08月12日
关于用户登录为什么不保存在应用程序的Session中呢
回复 点赞
sonnchuui520 2013年08月12日
引用 7 楼 luckyrandom 的回复:
建一个永久表,记录程序登录的SPID及程序登录用户名即可
谢谢回复! 但是在触发器中不知道当前是哪个用户啊?
回复 点赞
Q315054403 2013年08月12日
建一个永久表,记录程序登录的SPID及程序登录用户名即可
回复 点赞
sonnchuui520 2013年08月12日
引用 4 楼 hdhai9451 的回复:
每一次登录后,你都返回用户名ID和机器名,并且把它当成全局变量。 下次操作时直接用这个全局变量去更新别的就可以了。 每个表都建用触器,这样不好。
谢谢回复! 这个触发器是现在已经用了的,不能改啊,触发器还做了其他功能,就是备份数据,在追加和更新删除的时候,都要往备份表里追加数据。 还有系统使用了Seasar,使用全局变量的话,多个用户的时候就乱了,因为都用的同一个变量。 除非使用SESSION。
回复 点赞
sonnchuui520 2013年08月12日
引用 3 楼 wwwwgou 的回复:
没用过postgresql数据库。不太明白它的用法。 想问一下,楼主是否这样:先创建一个临时表,然后,往某些表中INSERT或UPDATE,同时要记录这个操作是哪个登陆用户所为。上面这些操作,是在同一个存储过程中?
不在一个存储过程。 这样说吧,首先开启了个数据库事物,然后执行一个sql(sqlserver里只能是存储过程或是PLSQL语句)创建了一个临时表,然后执行另一个往某个表中INSERT或UPDATE的sql语句,这个语句执行时会触发触发器,在触发器里对当前更新或追加的数据做一些修改(就是设定用户名和机器名),然后更新或插入到数据库,然后提交事物。
回复 点赞
Andy__Huang 2013年08月12日
每一次登录后,你都返回用户名ID和机器名,并且把它当成全局变量。 下次操作时直接用这个全局变量去更新别的就可以了。 每个表都建用触器,这样不好。
回复 点赞
发动态
发帖子
疑难问题
创建于2007-09-28

9304

社区成员

12.1w+

社区内容

MS-SQL Server 疑难问题
社区公告
暂无公告