web-dev-qa-db-ja.com

テーブルをストアドプロシージャに渡す

テーブルの名前をストアドプロシージャに渡すことはできますか?

たとえば、同じテーブルの複数のビューがあるとします。それらはすべてまったく同じ構造です。

どのビューでも実行できるストアドプロシージャが必要です。

何かのようなもの:

create procedure myprocedure
@tableName varchar(50) = ''
select blah from @tableName where blah = blah2 

これをやろうとすると、

Must declare the table variable @tablename

どうすればこれを行うことができますか?

6
dublintech

ビューを作成する代わりに、インラインテーブル値関数を作成してみませんか-効果的にパラメーター化されたビュー。基本的には、ビューとパラメーターのすべての利点が得られます。

TVFで実行できるもう1つのことは、次のようなものです。

SELECT yourtable.*
FROM yourtable
INNER JOIN ranges
    ON yourtable.date BETWEEN ranges.start AND ranges.end
WHERE ranges.name = @range_name

これで範囲に名前が付けられました(スキーマを変更せずに簡単に管理できるテーブル内)。これにより、同じ名前の複数の範囲もかなりシームレスに処理されます。ただし、範囲が重複している場合は、結合が両方に一致するため、重複する可能性があります。

また、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');

この部分:

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

各ログアイテムが(日付によって)適合する範囲に結合され、各範囲はそれらが属するグループに結合されますが、選択されたグループのみが使用されます。

11
Cade Roux

オブジェクト名はパラメーター化できません。

動的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
_

sysnameは(現在)nvarchar(128)として定義されていることに注意してください。

10
Jon Seigel

私はあなたの最善の策はこれを達成するために動的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
5
Thomas Stringer