用于计数动态表项的 MS SQL 存储过程
Posted
技术标签:
【中文标题】用于计数动态表项的 MS SQL 存储过程【英文标题】:MS SQL Stored Procedure for counting Dynamic table items 【发布时间】:2012-07-21 12:49:46 【问题描述】:我在下面的存储过程中写了这个并且得到了不正确的语句。
ALTER PROCEDURE dbo.[Counter]
@TableName VARCHAR(100)
AS
BEGIN
DECLARE @Counter INT
DECLARE @SQLQ VARCHAR(200)
SET NOCOUNT ON;
--SET @TableName = 'Member';
SET @SQLQ = 'SELECT COUNT(*) FROM dbo.[' + @TableName + ']';
--Preparing the above sql syntax into a new statement(get_counter).
--Getting an error here I had googled the prepare statement but don't know why facing this error.
PREPARE get_counter FROM @SQLQ;
@Counter = EXEC get_counter; -- here @resutl gets the value of the count.@TableName
DEALLOCATE PREPARE get_counter; -- removing the statement from the memory.
END
然后我又写了一篇:
ALTER PROCEDURE dbo.[Counter]
@TableName VARCHAR(100)
AS
BEGIN
DECLARE @Counter INT
DECLARE @SQLQ VARCHAR(200)
SET NOCOUNT ON;
--SET @TableName = 'Member';
SET @SQLQ = 'SELECT COUNT(*) FROM dbo.[' + @TableName + ']';
--Preparing the above sql syntax into a new statement(get_counter).
Execute @SQLQ; -- here @resutl gets the value of the count.@TableName
--DEALLOCATE PREPARE get_counter; -- removing the statement from the memory.
Return @Counter;
END
它运行正常,但我无法在 Counter 中得到结果,请任何人帮助我(我知道我没有为计数器分配任何值,但如果我这样做了,我会出错)。
在你回答马丁之后,我已经用你的代码替换了我的代码:
ALTER PROCEDURE dbo.[Counter] @SchemaName SYSNAME = 'dbo' , @TableName SYSNAME
AS
BEGIN
SET NOCOUNT ON;
DECLARE @SQLQ NVARCHAR(1000)
DECLARE @Counter INT;
SET @SQLQ = 'SELECT @Counter = COUNT(*) FROM ' +
Quotename(@SchemaName) + '.' + Quotename(@TableName);
EXEC sp_executesql
@SQLQ ,
N'@Counter INT OUTPUT',
@Counter = @Counter OUTPUT
Return SELECT @Counter
END
现在我已经找回了它。
ALTER PROCEDURE dbo.[CreateBusinessCode]
@MemberID bigint,
@len int,
@RewardAccountID bigint,
@ConnectionStatusID tinyint,
@Assign smalldatetime
AS
BEGIN
SET NOCOUNT ON;
DECLARE @counter INT
EXEC @counter = dbo.Counter 'dbo','member';
Select @counter;
END
【问题讨论】:
【参考方案1】:您应该使用SYSNAME
作为对象标识符,使用Quotename
而不是自己连接方括号。
ALTER PROCEDURE dbo.[Counter] @TableName SYSNAME,
@SchemaName SYSNAME = 'dbo'
AS
BEGIN
SET NOCOUNT ON;
DECLARE @SQLQ NVARCHAR(1000)
DECLARE @Counter INT;
SET @SQLQ = 'SELECT @Counter = COUNT(*) FROM ' +
Quotename(@SchemaName) + '.' + Quotename(@TableName);
EXEC sp_executesql
@SQLQ ,
N'@Counter INT OUTPUT',
@Counter = @Counter OUTPUT
SELECT @Counter
END
【讨论】:
优秀的@Martin Smith。你能解释一下 EXEC 行的代码吗? 我想我从这个msdn.microsoft.com/en-us/library/ms175170%28v=sql.105%29.aspx得到了解释【参考方案2】:在 SQL Server 中,如果要将结果放入变量中,有两种选择。
首先是使用游标。
二是做动态SQL:
declare @sql varchar(max) = whatever;
declare @cnt int;
declare @cntTable table as (cnt int);
insert into @cntTable
exec(@sql);
select @cnt = t.cnt
from @cntTable
这很麻烦,但其中一个确实有效。
【讨论】:
如果尝试 Select 语句而不是 insert into 语句会发生什么?你能解释一下吗? 这行不通。您可以将 exec 语句的输出插入到表中。您无法从中进行选择。 (对于 select,SQL Server 需要在编译查询时知道表的结构。它没有 exec 语句的信息。)【参考方案3】:试试这个。它不会查询实际表,但会为您提供行数。如果您有大表并且需要近似计数,这是更好的方法。
ALTER PROCEDURE dbo.[Counter]
@TableName VARCHAR(100)
AS
begin
declare @objectid int,@counter int
select @objectid = object_id from sys.all_objects where name = @tablename and schema_id=SCHEMA_ID('dbo')
select @counter = sum(rows) from sys.partitions where object_id= @objectid
and index_id in (0,1)
select @counter
end
go
【讨论】:
谢谢。这也很有帮助。以上是关于用于计数动态表项的 MS SQL 存储过程的主要内容,如果未能解决你的问题,请参考以下文章
如何删除 MS SQL Server 存储过程中的 While 循环? [关闭]