贴子只代表个人看法和观点,仅作交流使用,如有错误,敬请指正。
- SQL code
--建立测试环境IF object_id('tb') IS NOT NULL DROP TABLE tbGOCREATE TABLE tb(id INT IDENTITY(1,1),v VARCHAR(10))GOINSERT tb SELECT 'a'UNION ALL SELECT 'b'INSERT tb SELECT 'x'UNION ALL SELECT 'z'GO
(1)字串变量当数据库对象用
- SQL code
--=**********************************************--为什么我执行下面的语句选不到正确数据CREATE PROC p(@field VARCHAR(10),--字段名@value VARCHAR(10) --值)AS SELECT * FROM tb WHERE @[email protected]GOEXEC p 'v','a'GODROP PROC pGO
--为什么我执行下面语句报错
- SQL code
CREATE PROC p(@table VARCHAR(10),--表名@value VARCHAR(10) --值)AS SELECT * FROM @table WHERE [email protected]
说明:
在这二个存储过程中,@table,@field,@value都被定义为varchar
第一个实际上执行的是两个变量的比较,它的作用相当于
IF @[email protected]
SELECT * FROM tb
语法未错,意思上却大错特错
第二个实际上执行的是
SELECT * FROM 一个字串 WHERE [email protected]
如何能从一个字串中查询结果集呢?错误的把字串当成表对象来理解.
[email protected],它是个字段,而非表对象,不是object
可以用EXEC执行动态语句来解决,比如
- SQL code
EXEC('SELECT * FROM [' + @table + '] WHERE v=''' + @value + '''')
(2)为什么我在执行一个批语句(可能是存储过程,
也可能是个FUNCTION,也可能只是几条语句的组合)时,
提示错误,我照着提示的错误,检查,但是那里没有报错啊
--=**********************************************
比如,上面的第二个存储过程,@table明明是存储过程的输入参数,[email protected]
在上面,我已经讲了这句为什么出错的原因,
[email protected],那么那句select是不会有问题的,
但表变量不能用做输入参数。但它为什么这样提示呢?
这与sql内部机制有关,sql查询语句执行前先由命令解析器进行语法检查,如果语法检查未通过,
会扔出错误信息(通常这里的提示是精确的),
当语法检查通过,则将其编译为可执行的内部格式(查询树),
而非语法错误时,因为是执行时报错,执行期间是内部格式代码,只能扔出个大致错误信息.
了解了这一点,当您的sql语句报错后,先检查是否语法错误,
如果不是,那么需要仔细检查了,因为按着错误提示去找,很有可能兜圈子。
--=**********************************************
(3)[email protected],却提示我变量不存在?
- SQL code
--=**********************************************DECLARE @field VARCHAR(10),@n INTSET @field='v'EXEC('SELECT @n=COUNT(*) FROM tb WHERE [' + @field + ']=''a''')
上面有三条语句:
rows 语句
1 定义两变量
2 [email protected]
3 执行动态语句
那么这三条语句,在执行时进行语法检查和编译,大至为:
- SQL code
DECLARESETEXEC
这是编译后要执行三步操作,它们在一进程空间中进行编译。
随着语句的运行,exec内部的语句被购造成'select @n=count(*) from tb where v=''a'''
这时,EXEC要执行的这条语句,继续要被命令解析器进行检查和编译,
它的编译内存空间与外部这个批不同,术语我可能表达不太清楚,
只想说明一点,动态语句在执行过程中才被首次编译,所以在这个空间中,[email protected]
解决方式,sqlserver为我们提供了sp_executesql来完成这个操作。
上面要完成的操作,可以改写为:
- SQL code
DECLARE @field VARCHAR(10),@n INT,@sql NVARCHAR(4000)SET @field='v'SET @sql=N'SELECT @n=COUNT(*) FROM tb WHERE [' + @field + ']=''a'''EXEC sp_executeSQL @sql,[email protected] INT OUTPUT',@n OUTPUTSELECT @n--=**********************************************
(4)以下语句为什么提示我临时表不存在,明明我生成了临时表的
--=**********************************************
- SQL code
EXEC('SELECT * INTO # FROM tb')SELECT * FROM #
说明:
[email protected]空间的问题。
我们再联合局部临时表的生名周期,局部临时表在当间会话进程中有效
EXEC内部的语句是新开辟的一个进程空间执行的,所以当它执行完毕后,