Search code examples
sqlcaseuser-defined-functionssql-in

Can a UDF return a list that can be used with an "IN" keyword?


With this SQL snippet from my SPROC:

            -- Having the PanelPayout role gives you more transaction types to look for, hence the CASE statement.
            CASE WHEN EXISTS (SELECT RoleID FROM aspnet_UsersInRoles ur WHERE ur.RoleID = 'DEDCD456-A25A-43C5-8125-A1D1223B19EC' AND ur.UserID = s.aspnet_UserID) THEN
                (SELECT ISNULL(SUM(Amount), 0) FROM TransactionsLog payouts WHERE 
                    payouts.StaffID = s.ID 
                    AND payouts.TransactionType IN (48, 49, 3, 16, 292, 293)
                    AND (payouts.OrderDate >= dbo.Date(@date) AND payouts.OrderDate <= dbo.EndOfDay(@date))
                    AND @shift = CASE @shift WHEN 0 THEN 0 ELSE dbo.GetShiftByDate(payouts.OrderDate) END
                ) 
            ELSE
                (SELECT ISNULL(SUM(Amount), 0) FROM TransactionsLog payouts WHERE 
                    payouts.StaffID = s.ID 
                    AND payouts.TransactionType IN (48, 49, 3) 
                    AND (payouts.OrderDate >= dbo.Date(@date) AND payouts.OrderDate <= dbo.EndOfDay(@date))
                    AND @shift = CASE @shift WHEN 0 THEN 0 ELSE dbo.GetShiftByDate(payouts.OrderDate) END
                ) 
            END     

And this works fine. However, overall, the query is not returning what I want due to some issues in how the database was originally structured 7 years ago. So, I'm going to use C# to do what I need to do. My question is can a UDF return a list of ints that could be used with IN, so I would only need to write

                (SELECT ISNULL(SUM(Amount), 0) FROM TransactionsLog payouts WHERE 
                    payouts.StaffID = s.ID 
                    AND payouts.TransactionType IN dbo.PayoutTransactionsValidForStaff(s.ID)
                    AND (payouts.OrderDate >= dbo.Date(@date) AND payouts.OrderDate <= dbo.EndOfDay(@date))
                    AND @shift = CASE @shift WHEN 0 THEN 0 ELSE dbo.GetShiftByDate(payouts.OrderDate) END
                ) 

where PayoutTransactionsValidForStaff(s.ID) would return the list of ints needed to check? I would imagine it could be a table-valued function, but I don't have time to test because I gotta get this update shipped. Just wondering if anyone knew off the top of their head. Thanks!


Solution

  • Yes, you can create a table valued function in SQL which returns a table instead of a scalar result. You can use the result of this in a Sql in statement

    http://msdn.microsoft.com/en-us/library/ms191165(v=sql.105).aspx

    CREATE FUNCTION dbo.Test()
    RETURNS @funcTable TABLE 
    (
        -- Columns returned by the function
        ID int PRIMARY KEY NOT NULL    
    )
    AS 
    -- Return some arbitrary ints
    BEGIN
        INSERT @funcTable VALUES (1)
        INSERT @funcTable VALUES (2)
    
        RETURN 
    END
    
    GO
    
    -- Test it - insert 1,2,3 into a table var
    DECLARE @SomeTable table (ID int)
    INSERT INTO @SomeTable VALUES (1)
    INSERT INTO @SomeTable VALUES (2)
    INSERT INTO @SomeTable VALUES (3)
    
    -- Select from @SomeTable where the ID is in the result of the UDF
    select * from @SomeTable WHERE ID IN (SELECT ID FROM dbo.Test())