投稿する前に、USD関数の開発に関するいくつかの記事を読みましたが、私の問題の解決策は見つかりませんでした...これは次のとおりです。
私は、バスケットボール選手を保存し、ID、年齢、身長、名前の列で構成される非常にシンプルなデータベースを持っています。私がやりたいのは、1つのパラメータ@set varchar(10)を使用して関数 'height'を実装することです。1つの@set値に応じて、さまざまな選択ステートメントがトリガーされます。
私が実装しようとしていたのは疑似コードです:
CREATE FUNCTION [dbo].[age](@set varchar(10))
RETURNS TABLE
AS
BEGIN
IF (@set = 'tall')
SELECT * from player where height > 180
ELSE IF (@set = 'average')
SELECT * from player where height >= 155 and height <=175
ELSE IF (@set = 'low')
SELECT * from player where height < 155
END
誰かが私にそれを実装する方法のヒントを教えてくれませんか?
最も単純な形が常に最高です
CREATE FUNCTION [dbo].[age](@set varchar(10))
RETURNS TABLE
AS RETURN
SELECT * from player
where ((@set = 'tall' and height > 180)
or (@set = 'average' AND height >= 155 and height <=175)
or (@set = 'low' AND height < 155))
GO
このフォームはINLINEテーブル関数と呼ばれます。つまり、SQL Serverは、それを自由に拡張して、プレーヤーを直接、より大きなクエリのインラインで他のテーブルに結合し、実行させることができます無限に1 より良い複数ステートメントのテーブル値関数より。
ただし、範囲を完全にするためにこれを使用することもできます(175と180の間にギャップがあります)。
where ((@set = 'tall' and height > 180)
or (@set = 'average' AND height >= 155 and height <= 180)
or (@set = 'low' AND height < 155))
SQL Serverは、変数@setが解析されるときにブランチの短絡を処理します。
1誇張だが少しだけ
あなたは近くにいた。複数ステートメントのテーブル値関数を使用するには、関数に戻りテーブルを指定してデータを設定する必要があります。
CREATE FUNCTION [dbo].[age](@set varchar(10))
RETURNS @Players TABLE
(
-- Put the players table definition here
)
AS
BEGIN
IF (@set = 'tall')
INSERT INTO @Players SELECT * from player where height > 180
ELSE IF (@set = 'average')
INSERT INTO @Players SELECT * from player where height >= 155 and height <=175
ELSE IF (@set = 'low')
INSERT INTO @Players SELECT * from player where height < 155
RETURN -- @Players (variable only required for Scalar functions)
END
Richardの回答が示すように、インラインTVFを使用することをお勧めします。ステートメントからのテーブルの戻りを推測できます。
また、マルチステートメントとインラインTVFはまったく異なる点にも注意してください。インラインTVFはオプティマイザにとってブラックボックスではなく、オプティマイザが同じ実行プラン内の他のテーブルやビューで物事を再配置できるという点で、パラメータ化されたビューに似ています。
なぜこれをハードコーディングし、高さテーブルを作成し、範囲に有効なすべての高さを取得するのですか
SELECT * from player p
join Heights h on p.height between h.heightStart and h.heightEnd
WHERE h.height = @set
これはうまくいくはずです。
SELECT * FROM player
WHERE
height > CASE
WHEN @set = 'tall' THEN 180
WHEN @set = 'average' THEN 154
WHEN @set = 'low' THEN 0
END
<ケースはお楽しみに残しておきます。
IF条件で次のようにTable値関数を使用できます。
CREATE function [dbo].[AA]
(
@abc varchar(10)
)
Returns @mytable table
(
supname nvarchar(10), [add] nvarchar(10)
)
AS
begin
-- lOAD WHATEVER THINGS YOU REQUIRED INTO THIS DYNAMIC TABLE
if (@abc ='hh')
insert into @mytable (supname, [add]) values ('hh','gg'+ @abc)
else
insert into @mytable (supname, [add]) values ('else','gg'+ @abc)
return
end
--select * from [dbo].[AA]('SDAASF')
このようなもの:
CREATE FUNCTION [dbo].[Age](@set VARCHAR(10))
RETURNS @Players TABLE
(
playerId INT,
Name VARCHAR(50)
)
AS
BEGIN
INSERT INTO @Players
SELECT playerId, Name
FROM player
WHERE CASE WHEN @set = 'tall' AND height > 180 THEN 1
WHEN @set = 'average' AND height BETWEEN 155 AND 180 THEN 1
WHEN @set = 'low' AND height < 155 THEN 1 ELSE 0 END = 1
RETURN
END
Itzik Ben-Ganの著書「TSQL Querying」によると(Itzik Ben-Gan et al、(c)2015 Microsoft Press、ISBN 978-0-7356-8504-8、P. 215) "...インラインTVFは優れたツールであり、UDFのパフォーマンスの問題なしにロジックのカプセル化と再利用を可能にします..."
彼はまた、「...ビューのような再利用可能なテーブル式が必要ですが、入力パラメータをテーブル式に渡す必要がある場合も... TSQLはインラインテーブル値関数(TVF)を提供します。 "
このタイプの 'IF'(インライン関数-sys.objectsの特殊タイプ)は、 'RETURNS TABLE'出力指定子を使用しており、BEGIN/ENDを含めることはできないようです。構文と許容値は非常に制限されていますが、最適化とパフォーマンスは良好です。これらの要因は、@ rykによって見られるタイミングによって示されます。