編集注記最後に向かって更新されたバージョン
この回答はキャッシュを使用していませんが、関数への呼び出しの数を最小限に抑える必要があります。を使用してCTEs
myField1の個別の値を検索し、関数を使用してWebサービスの個別の値を検索し、これらをMyTableに結合します。以下の例はおそらくそれをより明確にします:
SQLフィドル
MS SQL Server 2008スキーマのセットアップ:
CREATE TABLE MyTable
(
ID int PRIMARY KEY IDENTITY,
MyField1 VARCHAR(1)
);
CREATE FUNCTION MyFunction
(
@input As VARCHAR(1)
)
RETURNS VARCHAR(10)
AS
BEGIN
-- This could be a CLR Function
-- Return the result of the function
RETURN CASE @input WHEN 'A' THEN 'aaaaaaaaaa' WHEN 'B' THEN 'bbbbbbbbbb' ELSE 'ccccccccc' END
END;
-- DATA SET UP
DECLARE @i INT = 0
DECLARE @Field VARCHAR(1)
WHILE @i < 1000
BEGIN
SELECT @Field = CASE @i % 3 WHEN 1 THEN 'A' WHEN 2 THEN 'B' ELSE 'C' END
INSERT INTO MyTable (MyField1) VALUES (@Field)
SET @i = @i + 1
END
クエリ1:
;WITH DistinctMyField1CTE
AS
(
SELECT DISTINCT MyField1
FROM MyTable
),
LookupValuesCTE
AS
(
SELECT MyField1, dbo.MyFunction(MyField1) As MyOutputField
FROM DistinctMyField1CTE
)
SELECT TOP 20 T1.Id, T1.MyField1, T2.MyOutputField
FROM MyTable T1
INNER JOIN LookupValuesCTE T2
ON T1.MyField1 = T2.MyField1
ORDER BY T1.ID
結果:
| ID | MYFIELD1 | MYOUTPUTFIELD |
---------------------------------
| 1 | C | ccccccccc |
| 2 | A | aaaaaaaaaa |
| 3 | B | bbbbbbbbbb |
| 4 | C | ccccccccc |
| 5 | A | aaaaaaaaaa |
| 6 | B | bbbbbbbbbb |
| 7 | C | ccccccccc |
| 8 | A | aaaaaaaaaa |
| 9 | B | bbbbbbbbbb |
| 10 | C | ccccccccc |
| 11 | A | aaaaaaaaaa |
| 12 | B | bbbbbbbbbb |
| 13 | C | ccccccccc |
| 14 | A | aaaaaaaaaa |
| 15 | B | bbbbbbbbbb |
| 16 | C | ccccccccc |
| 17 | A | aaaaaaaaaa |
| 18 | B | bbbbbbbbbb |
| 19 | C | ccccccccc |
| 20 | A | aaaaaaaaaa |
編集:
上記のSQLプロファイラートレースを確認すると、UDFへの1000回の呼び出しが表示されます。つまり、クエリアナライザーは、CTEを拡張し、行ごとに1回UDFを呼び出すプランを生成しています。
以下では、テーブル変数を使用して、UDFが3回だけ呼び出されるようにします。これをSQLプロファイラーで追跡しましたが、はるかに効率的です。これは、上記と同じテーブルと関数を使用します。SQLFiddleを添付する必要があります
SQLフィドル
MS SQL Server 2008スキーマのセットアップ:
CREATE TABLE MyTable
(
ID int PRIMARY KEY IDENTITY,
MyField1 VARCHAR(1)
);
CREATE FUNCTION MyFunction
(
@input As VARCHAR(1)
)
RETURNS VARCHAR(10)
AS
BEGIN
-- This could be a CLR Function
-- Return the result of the function
RETURN CASE @input WHEN 'A' THEN 'aaaaaaaaaa' WHEN 'B' THEN 'bbbbbbbbbb' ELSE 'ccccccccc' END
END;
-- DATA SET UP
DECLARE @i INT = 0
DECLARE @Field VARCHAR(1)
WHILE @i < 1000
BEGIN
SELECT @Field = CASE @i % 3 WHEN 1 THEN 'A' WHEN 2 THEN 'B' ELSE 'C' END
INSERT INTO MyTable (MyField1) VALUES (@Field)
SET @i = @i + 1
END
クエリ1:
DECLARE @TempTable TABLE
(
MyField1 VARCHAR(1) PRIMARY KEY,
MyOutputField VARCHAR(10) NULL
)
INSERT INTO @TempTable (MyField1)
SELECT DISTINCT MyField1
FROM MyTable
-- UPDATE Separately otherwise the function gets called
-- for every row in MyTable
UPDATE @TempTable
SET MyOutputField = dbo.MyFunction(MyField1)
SELECT TOP 20 T1.ID, T1.MyField1, T2.MyOutputField
FROM MyTable T1
INNER JOIN @TempTable T2
ON T1.MyField1 = T2.MyField1
結果:
| ID | MYFIELD1 | MYOUTPUTFIELD |
---------------------------------
| 2 | A | aaaaaaaaaa |
| 5 | A | aaaaaaaaaa |
| 8 | A | aaaaaaaaaa |
| 11 | A | aaaaaaaaaa |
| 14 | A | aaaaaaaaaa |
| 17 | A | aaaaaaaaaa |
| 20 | A | aaaaaaaaaa |
| 23 | A | aaaaaaaaaa |
| 26 | A | aaaaaaaaaa |
| 29 | A | aaaaaaaaaa |
| 32 | A | aaaaaaaaaa |
| 35 | A | aaaaaaaaaa |
| 38 | A | aaaaaaaaaa |
| 41 | A | aaaaaaaaaa |
| 44 | A | aaaaaaaaaa |
| 47 | A | aaaaaaaaaa |
| 50 | A | aaaaaaaaaa |
| 53 | A | aaaaaaaaaa |
| 56 | A | aaaaaaaaaa |
| 59 | A | aaaaaaaaaa |