web-dev-qa-db-ja.com

TSQL-テーブル値関数内のIf..Elseステートメント-通過できません

投稿する前に、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

誰かが私にそれを実装する方法のヒントを教えてくれませんか?

19
Artur

最も単純な形が常に最高です

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誇張だが少しだけ

20
RichardTheKiwi

あなたは近くにいた。複数ステートメントのテーブル値関数を使用するには、関数に戻りテーブルを指定してデータを設定する必要があります。

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はオプティマイザにとってブラックボックスではなく、オプティマイザが同じ実行プラン内の他のテーブルやビューで物事を再配置できるという点で、パラメータ化されたビューに似ています。

16
Cade Roux

なぜこれをハードコーディングし、高さテーブルを作成し、範囲に有効なすべての高さを取得するのですか

SELECT * from player p
join Heights h on p.height between h.heightStart and h.heightEnd 
WHERE h.height  = @set
11
SQLMenace

これはうまくいくはずです。

SELECT * FROM player 
WHERE
  height > CASE 
            WHEN @set = 'tall' THEN 180
            WHEN @set = 'average' THEN 154
            WHEN @set = 'low' THEN 0
          END

<ケースはお楽しみに残しておきます。

3
Hogan

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')
2
user2316060

このようなもの:

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
2
Lamak

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によって見られるタイミングによって示されます。

0
CubeSpark