Vraag TSQL - If..Else verklaring binnen Tabel-Gewaardeerde functies - kan niet doorgaan


Alvorens te posten heb ik enkele artikelen gelezen over het ontwikkelen van USD-functies, maar ik heb geen oplossingen voor mijn probleem gevonden ... wat als volgt is:

Ik heb een heel eenvoudige database, die basketbalspelers opslaat en bestaat uit de kolom ID, Age, Height en Name. Wat ik zou willen doen is het implementeren van een functie 'hoogte' met één parameter @set varchar (10), die afhankelijk van een @set-waarde verschillende selectiestatussen activeert

wat ik probeerde te implementeren was in psuedo-code:

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

Kan iemand me een hint geven hoe ik het moet implementeren?


15
2018-04-04 20:58


oorsprong


antwoorden:


De eenvoudigste vorm is altijd de beste

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

Dit formulier wordt de INLINE-tabelfunctie genoemd, wat betekent dat SQL Server het gratis kan uitbreiden om de speler rechtstreeks met andere tabellen in de rij van een grotere query samen te voegen, waardoor het presteert oneindig1 beter dan een tafelwaardetabel met meerdere afschriften.

Je hebt hier misschien de voorkeur aan, zodat je reeksen compleet zijn (je hebt een opening tussen 175 en 180)

where ((@set = 'tall' and height > 180)
   or (@set = 'average' AND height >= 155 and height <= 180)
   or (@set = 'low' AND height < 155))

SQL Server zorgt voor kortsluiting van de takken wanneer de variabele @set wordt geparseerd.

1 overdrijving, maar slechts in geringe mate


17
2018-04-04 21:12



Je was dichtbij. Voor het gebruik van een tabelwaardetabel met meerdere afschriften moet de retourtabel worden opgegeven en ingevuld in de functie:

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

Ik zou aanraden om een ​​inline TVF te gebruiken, zoals Richard's antwoord laat zien. Het kan de tabelterugloop uit uw verklaring afleiden.

Merk ook op dat een multi-statement en inline TVF's echt heel anders zijn. Een inline TVF is minder een black-box voor de optimizer en meer een geparametriseerde weergave in termen van de optimalisator die in staat is om dingen te herschikken met andere tabellen en weergaven in hetzelfde uitvoeringsplan.


13
2018-04-04 21:44



Waarom codeer je dit, maak een hoogtetabel en pak vervolgens alle hoogtes die geldig zijn voor het bereik

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

10
2018-04-04 21:02



Dit zou moeten werken.

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

Ik zal de <case voor je plezier achterlaten.


3
2018-04-04 21:01



Iets zoals dit:

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
2018-04-04 21:06



We kunnen de tabelwaarde-functie op de volgende manier gebruiken met IF-voorwaarden erop.

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

0
2018-04-24 14:37



Volgens Itzik Ben-Gan in zijn boek "TSQL Querying" (Itzik Ben-Gan et al, (c) 2015 Microsoft Press, ISBN 978-0-7356-8504-8, P. 215) "...Ik vind inline TVF's een geweldig hulpmiddel, waardoor de logica en herbruikbaarheid kunnen worden ingekapseld zonder dat er problemen met de prestaties van UDF ..."

Hij zegt ook dat als je dat nodig hebt "... een herbruikbare tabelexpressie zoals een weergave, maar u moet ook invoerparameters doorgeven aan de tabelexpressie ... TSQL biedt in line table-valued functions (TVFs). "

Dit type 'IF' ( inline-functie - een ander type in sys.objects ) gebruikt de uitvoerspecificatie 'RETOURTAFEL' en schijnbaar kan deze geen BEGIN / END bevatten. De syntaxis en rechten zijn erg beperkend, maar we zien een goede optimalisatie en prestaties. Deze factoren worden aangegeven door de tijdstippen die @ryk ziet.


0
2017-10-27 16:53