将表传入存储过程

dub*_*ech 6 sql-server-2008 sql-server stored-procedures

是否可以将表名传入存储过程?

例如,假设您有同一个表的多个视图。它们都具有完全相同的结构。

您需要一个可以为任何视图运行的存储过程。

就像是:

create procedure myprocedure
@tableName varchar(50) = ''
select blah from @tableName where blah = blah2 
Run Code Online (Sandbox Code Playgroud)

当我尝试这样做时,我得到

Must declare the table variable @tablename
Run Code Online (Sandbox Code Playgroud)

任何想法我怎么能做到这一点?

Cad*_*oux 11

与其创建视图,不如创建一个内联表值函数——实际上是一个参数化视图。您基本上可以获得视图和参数的所有好处。

您可以在 TVF 中做的另一件事是这样的:

SELECT yourtable.*
FROM yourtable
INNER JOIN ranges
    ON yourtable.date BETWEEN ranges.start AND ranges.end
WHERE ranges.name = @range_name
Run Code Online (Sandbox Code Playgroud)

现在您的范围有名称(在一个表中,它们可以在不更改架构的情况下轻松管理) - 这也可以相当无缝地处理具有相同名称的多个范围,尽管如果范围重叠,由于连接匹配两者,您可能会有重复。

另外,请考虑避免 BETWEEN:

我强烈建议您重新考虑您的要求,并且在此处提出问题时,请务必包含更多关于您的动机的信息,因为当您提出问题时对解决方案具有先入为主的概念,您很可能会得到一个次优的解决方案。(就像给定的动态 SQL 解决方案不会轻易适用于您的 OR 案例,但有关问题空间的信息隐藏在您的评论中)

来自:http : //sqlfiddle.com/#!6/a628a/1

CREATE TABLE LogData (
  Id INT IDENTITY NOT NULL
  ,Dt DATETIME NOT NULL
  ,Data VARCHAR(max) NOT NULL
);

CREATE TABLE Ranges (
  Id INT IDENTITY NOT NULL
  ,Name VARCHAR(50) NOT NULL
  ,DtStart DATETIME NOT NULL
  ,DtEnd DATETIME NOT NULL
);

CREATE TABLE Groups (
  Id INT IDENTITY NOT NULL
  ,Name VARCHAR(50) NOT NULL
);

CREATE TABLE RangeGroups (
  RangeId INT NOT NULL
  ,GroupId INT NOT NULL
);

INSERT INTO LogData (Dt, Data)
VALUES ('2011-11-23 11:00', 'before thanksgiving day')
       ,('2011-11-24 11:00', 'on thanksgiving day')
       ,('2011-12-24 11:00', 'on christmas eve')
       ,('2011-12-25 11:00', 'on christmas day')
       ,('2012-11-21 11:00', 'before thanksgiving day')
       ,('2012-11-22 11:00', 'on thanksgiving day')
       ,('2012-12-24 11:00', 'on christmas eve')
       ,('2012-12-25 11:00', 'on christmas day');

INSERT INTO Ranges (Name, DtStart, DtEnd)
VALUES ('THANKSGIVING2011', '2011-11-24', '2011-11-25')
       ,('CHRISTMASEVE2011', '2011-12-24', '2011-12-25')
       ,('CHRISTMASDAY2011', '2011-12-25', '2011-12-26')
       ,('BOXINGDAY2011', '2011-12-26', '2011-12-27')
       ,('NEWYEARSEVE2011', '2011-12-31', '2012-01-01')
       ,('NEWYEARSDAY2012', '2012-01-01', '2012-01-02')
       ,('THANKSGIVING2012', '2012-11-22', '2012-11-23')
       ,('CHRISTMASEVE2012', '2012-12-24', '2012-12-25')
       ,('CHRISTMASDAY2012', '2012-12-25', '2012-12-26')
       ,('BOXINGDAY2012', '2012-12-26', '2012-12-27')
       ,('NEWYEARSEVE2012', '2012-12-31', '2013-01-01')
       ,('NEWYEARSDAY2013', '2013-01-01', '2013-01-02');

INSERT INTO Groups (Name)
VALUES ('HOLIDAYS2011')
       ,('HOLIDAYS2012')
       ,('ANYCHRISTMAS');

INSERT INTO RangeGroups (RangeId, GroupId)
SELECT Id, (SELECT Id FROM Groups WHERE Name = 'HOLIDAYS2011')
FROM Ranges WHERE Name LIKE '%2011';

INSERT INTO RangeGroups (RangeId, GroupId)
SELECT Id, (SELECT Id FROM Groups WHERE Name = 'HOLIDAYS2012')
FROM Ranges WHERE Name LIKE '%2012';

INSERT INTO RangeGroups (RangeId, GroupId)
SELECT Id, (SELECT Id FROM Groups WHERE Name = 'ANYCHRISTMAS')
FROM Ranges WHERE Name LIKE 'CHRISTMAS%';


CREATE FUNCTION dbo.JustDoIt(@GroupName VARCHAR(50))
RETURNS TABLE
RETURN (
SELECT LogData.*
FROM LogData
INNER JOIN Ranges ON LogData.Dt >= Ranges.DtStart
AND LogData.Dt < Ranges.DtEnd
INNER JOIN RangeGroups
ON RangeGroups.RangeId = Ranges.Id
INNER JOIN Groups
ON Groups.Id = RangeGroups.GroupId
AND Groups.Name = @GroupName
);

SELECT *
FROM dbo.JustDoIt('HOLIDAYS2011');

SELECT *
FROM dbo.JustDoIt('HOLIDAYS2012');

SELECT *
FROM dbo.JustDoIt('ANYCHRISTMAS');
Run Code Online (Sandbox Code Playgroud)

这部分:

SELECT LogData.*
FROM LogData
INNER JOIN Ranges ON LogData.Dt >= Ranges.DtStart
AND LogData.Dt < Ranges.DtEnd
INNER JOIN RangeGroups
ON RangeGroups.RangeId = Ranges.Id
INNER JOIN Groups
ON Groups.Id = RangeGroups.GroupId
AND Groups.Name = @GroupName
Run Code Online (Sandbox Code Playgroud)

意味着每个日志项都将加入它适合的范围(按日期),每个范围将加入它们所在的组,但只会使用所选的组。


Jon*_*gel 10

对象名称不能参数化。

您需要使用动态 SQL:

CREATE PROCEDURE MyProc
(
    @schemaName sysname,
    @tableName sysname,
    @blah2 int
)
AS
BEGIN

    SET NOCOUNT ON

    DECLARE @sql nvarchar(MAX)

    SET @sql = N'SELECT blah FROM '
        + QUOTENAME(@schemaName) + N'.' + QUOTENAME(@tableName) + N' WHERE blah = @blah2'

    EXEC sp_executesql @sql, N'@blah2 int', @blah2

END
Run Code Online (Sandbox Code Playgroud)

请注意,sysname(当前)定义为nvarchar(128).


Tho*_*ger 5

我认为你最好的选择是使用动态 SQL 来完成这个:

create procedure myprocedure
@tableName nvarchar(50) = ''
as

    declare @sql_cmd nvarchar(200) 
    set @sql_cmd = 'select blah from ' + QUOTENAME(@tableName) + ' where blah = blah2'

    exec (@sql_cmd)

go
Run Code Online (Sandbox Code Playgroud)