3

I have this procedure

ALTER PROCEDURE [dbo].GetHerdByUserProc(@user int)
As 
    begin
        Declare
            @GroupId uniqueidentifier,
            @UserTrade bit

        Set @GroupId = (select tbUser.group_id from tbUser where Userid = @user)
        Set @UserTrade = (select tbUser.isTrade from tbUser where Userid = @user)
        if @GroupId IS NOT NULL and @UserTrade = '1'
        Begin 
            select HerdId from tbUserHerds where tbUserHerds.UserId in (select Userid from tbUser where tbUser.Group_Id = @GroupId)
            return;
        END
        If @GroupId IS NOT NULL
        Begin   
            select HerdId from tbUserHerds where tbUserHerds.UserId = @user
            return;
        End
        return;
    End

It returns a list correctly except I would also like to run a query on the list that is returned and as far as I am aware I cannot write a query such as

Select * from GetHerdByUserProc 80

So I am looking the best way to convert this to a table-valued query.

I have changed the alter to say 'Create Function x(@user int) Returns Table As'

But that does not seam to work it starts screaming errors at me.

Any ideas? The Database Server is MSSQL2008

MatBailie
  • 83,401
  • 18
  • 103
  • 137
TheMonkeyMan
  • 8,622
  • 8
  • 27
  • 42
  • ***SQL*** is just the *Structured Query Language* - a language used by many database systems, but not a a database product... stuff like this is highly vendor-specific - so we really need to know what **database system** (and which version) you're using.... – marc_s Nov 01 '12 at 09:18

4 Answers4

3

Based on your Syntax, I'm going to assume SQL Server for now.

From BOL the Syntax for an inline function should be...

--Transact-SQL Inline Table-Valued Function Syntax 
CREATE FUNCTION [ schema_name. ] function_name 
( [ { @parameter_name [ AS ] [ type_schema_name. ] parameter_data_type 
    [ = default ] [ READONLY ] } 
    [ ,...n ]
  ]
)
RETURNS TABLE
    [ WITH <function_option> [ ,...n ] ]
    [ AS ]
    RETURN [ ( ] select_stmt [ ) ]
[ ; ]

With this format, you can not use SET, DECLARE, IF, etc. All you can use is a single SQL Statement. [If you need to use program flow, look to a multi-statement table valued function.]

It's a separate topic, but Inline Table Valued Functions have many performance efficiencies over their Multi-Statement equivilents. Nearly always, if you can do it Inline, you should do so.

As it happens, you can write your logic without the IF statements, and use just a single SQL Statement. This gives the following Inline Table Valued Function...

CREATE FUNCTION [dbo].GetHerdByUserProc(@user int)
RETURNS TABLE
RETURN
  SELECT
    herd.HerdID
  FROM
    tbUser          AS user
  INNER JOIN
    tbUser          AS group
      ON group.group_id = user.group_id
  INNER JOIN
    tbUserHerds     AS herd
      ON herd.UserID = group.UserID
  WHERE
        user.userID   = @userID
    AND user.isTrade  = 1
    AND user.group_id IS NOT NULL

  UNION ALL

  SELECT
    herd.HerdID
  FROM
    tbUser          AS user
  INNER JOIN
    tbUserHerds     AS herd
      ON herd.UserID = user.UserID
  WHERE
        user.userID    = @userID
    AND user.isTrade  <> 1
    AND user.group_id IS NOT NULL

The UNION ALL combined with the WHERE clauses effectively does your IF statements for you. (Do note, if user.isTrade can be NULL, you need to change user.isTrade <> 1 to something more like ISNULL(user.isTrade, 0) <> 1.)

Potentially, you could even simplify this down to a single query, though I would test it to see if it's actually any more efficient or not...

RETURN
  SELECT
    herd.HerdID
  FROM
    tbUser          AS user
  INNER JOIN
    tbUser          AS group
      ON (group.group_id = user.group_id AND user.isTrade = 1)
      OR (group.user_id  = user.userID)
  INNER JOIN
    tbUserHerds     AS herd
      ON herd.UserID = group.UserID
  WHERE
    user.userID = @userID
  • if group_id is NULL, the first join will never succeed.
  • then the two IF blocks are simulated by the OR.
MatBailie
  • 83,401
  • 18
  • 103
  • 137
1

You could store the results of the PROC in a temp table:

INSERT INTO #temptbl EXEC [dbo].GetHerdByUserProc(80)
SchmitzIT
  • 9,227
  • 9
  • 65
  • 92
  • Why the down-vote? Storing the results of the sp into a temp table will allow the OP to run queries against the result-set, without having to rewrite the code. – SchmitzIT Nov 01 '12 at 09:37
  • It doesn't need to be an SP, the OP doesn't want an SP, you can't call an SP from within a SQL Statment, so it's harder to join itself to itself *(as well as a lot of other lost functionality)*, this can only be done at one level of the SP call tree *(if an outer SP also uses this trick, it will fail)*. Mostly, the fact that it doesn't answer the OPs question, when it is perfectly answerable, and perfectly reasonable, and even recommended, that's why I'm adding your second -1. *[You don't even explain WHY this should be used in your answer, though your comment does go towards that.]* – MatBailie Nov 01 '12 at 09:51
  • 1
    The OP clearly states: "As far as i know I cannot use something like "Select * from GetHerdByUserProc 80". My answer shows that there is a way to accomplish what he wants, without the need to rewrite everything. – SchmitzIT Nov 01 '12 at 10:00
1

You need to define the structure of the table in the definition and then insert values into the declare table variable...

create function x
(
    @user int 
)
returns @t
( 
   herdid int
)
as
begin
    insert @t (herdid)
    select HerdId from tbUserHerds where tbUserHerds.UserId = @user
    -- or whatever...
    return 
end

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

podiluska
  • 50,950
  • 7
  • 98
  • 104
  • True for `multi-statement` TVFs. I would explicitly state that `Inline` TVFs are different, and have different restrictions and benefits. – MatBailie Nov 01 '12 at 09:52
0

you can simply write sql query using CASE statement . CASE statement is easiest way to handle Conditional Queries .

 Declare @GroupId uniqueidentifier,@UserTrade bit

 select HerdId 
 from tbUserHerds 
 where 
 1 = CASE 
    WHEN (select tbUser.group_id from tbUser where Userid = @user) IS NOT NULL 
    THEN 
        CASE 
            WHEN tbUserHerds.UserId = @user THEN 1 
            ELSE 0 
        END

    WHEN 
            (select tbUser.group_id from tbUser where Userid = @user) IS NOT NULL      and           (select tbUser.isTrade from tbUser where Userid = @user) = '1'
    THEN 
        CASE 
            WHEN tbUserHerds.UserId in (select Userid from tbUser     where tbUser.Group_Id = (select tbUser.group_id from tbUser where Userid = @user)) THEN 1 
            ELSE 0 
        END
END
Hiren Dhaduk
  • 2,760
  • 2
  • 19
  • 21