2017-07-03 4 views
0

私はテーブル値関数BとCを呼び出すテーブル値関数Aを持っています。関数BとCは、移行の一環として更新(変更)されていますが、テーブルAは更新されません。 Aを変更せずにAを再構築するにはどうすればよいですか?依存関係が更新されたときにSQL Serverでユーザー定義関数を再コンパイルする方法はありますか?

例(ロールバックがちょうど便宜のために追加されます)SQL Fiddle

BEGIN TRANSACTION 

SET NOCOUNT ON; 

CREATE TABLE DOGS 
(
    Id UNIQUEIDENTIFIER PRIMARY KEY, 
    Name NVARCHAR(255) NOT NULL, 
    Age INT NOT NULL, 
) 

INSERT INTO DOGS VALUES (NEWID(), 'Rocky', 12); 
INSERT INTO DOGS VALUES (NEWID(), 'Sammy', 2); 
INSERT INTO DOGS VALUES (NEWID(), 'Porthos', 5); 

CREATE TABLE CATS 
(
    Id UNIQUEIDENTIFIER PRIMARY KEY, 
    Name NVARCHAR(255) NOT NULL, 
    Age INT NOT NULL, 
) 

INSERT INTO CATS VALUES (NEWID(), 'Mr. T', 15); 
INSERT INTO CATS VALUES (NEWID(), 'Old Timer', 37); 
INSERT INTO CATS VALUES (NEWID(), 'Mittens', 1); 

SET NOCOUNT OFF; 

GO 
CREATE FUNCTION [GetCatsYoungerThan] 
(
    @age INT 
) 
RETURNS TABLE AS 
RETURN (
    SELECT Name FROM CATS WHERE Age < @age 
); 
GO 

CREATE FUNCTION [GetDogsYoungerThan] 
(
    @age INT 
) 
RETURNS TABLE AS 
RETURN (
    SELECT Name FROM DOGS WHERE Age < @age 
); 
GO 

CREATE FUNCTION [GetAnimalsYoungerThan] 
(
    @age INT 
) 
RETURNS TABLE AS 
RETURN (
    SELECT * FROM [GetCatsYoungerThan](@age) 
    UNION 
    SELECT * FROM [GetDogsYoungerThan](@age) 
); 
GO 

ALTER FUNCTION [dbo].[GetDogsYoungerThan] 
(
    @age INT 
) 
RETURNS TABLE AS 
RETURN (
    SELECT Name, Age FROM DOGS WHERE Age < @age 
); 
GO 

ALTER FUNCTION [dbo].[GetCatsYoungerThan] 
(
    @age INT 
) 
RETURNS TABLE AS 
RETURN (
    SELECT Name, Age FROM CATS WHERE Age < @age 
); 
GO 

EXEC sp_recompile '[GetAnimalsYoungerThan]'; 

--results 
SELECT * FROM [GetAnimalsYoungerThan](15); 

--Shows expected results 
SELECT * FROM [GetCatsYoungerThan](15) 
UNION 
SELECT * FROM [GetDogsYoungerThan](15) 

ROLLBACK TRANSACTION 

結果:

Name 
------- 
Mittens 
Porthos 
Rocky 
Sammy 

期待される結果:

Name Age 
----------- 
Mittens 1 
Porthos 5 
Rocky 12 
Sammy 2 

私の期待はsp_recompile機能を引き起こすということです再コンパイルする。しかし、それは起こっていないか、値がAで返ってきた値を更新するには不十分です。

私の元の計画は、データベース内のすべてのオブジェクトを次のコードを使って再コンパイルすることでしたが、sp_recompileが必要です。

DECLARE @ObjectName NVARCHAR(MAX); 
DECLARE MY_CURSOR CURSOR 
    LOCAL STATIC READ_ONLY FORWARD_ONLY 
FOR 
SELECT [ROUTINE_SCHEMA] + '.' + [ROUTINE_NAME] AS [NAME] 
FROM information_schema.routines 
WHERE [ROUTINE_SCHEMA] = 'my_domain'; 

OPEN MY_CURSOR 
FETCH NEXT FROM MY_CURSOR INTO @ObjectName 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    PRINT 'Recompiling ' + @ObjectName + '...'; 
    EXEC sp_recompile @ObjectName; 
    FETCH NEXT FROM MY_CURSOR INTO @ObjectName; 
END 
CLOSE MY_CURSOR 
DEALLOCATE MY_CURSOR 

ありがとうございました。

+1

これは、1) 'SELECT *'が悪魔であり、2)本当に 'WITH SCHEMABINDING'が必要な理由を示しています。確かに、今あなたは迷惑なエラーを得るが、少なくとも物事は静かに失敗しない。 –

答えて

2

これはSELECT *を使用した結果で、TVFの初期スキーマバインディングを実行した結果です。

あなたが実行することにより、望ましい結果を得ることができます。

効果的TVFへのスキーマがしようとすると避け、 ALTER x...

の冗長性なししかし、長期的には、再結合し

sp_refreshsqlmodule <tvf-name> 

SELECT *を使用してください。

+0

うわー!あなたへの私の帽子。完璧に働いた。 –

+0

将来、 'Select *'は避けています。残念ながら、これは継承されたデータベースです。 –

関連する問題