将存储过程转换为表值查询

时间:2012-11-01 09:16:01

标签: sql sql-server-2008 stored-procedures stored-functions sql-function

我有这个程序

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

它正确返回一个列表,除了我还要在返回的列表上运行查询,据我所知,我不能写一个查询,如

Select * from GetHerdByUserProc 80

所以我正在寻找将其转换为表值查询的最佳方法。

我已将更改更改为'Create Function x(@user int) Returns Table As'

但这并没有结束工作,它开始尖叫我的错误。

有什么想法吗?数据库服务器是MSSQL2008

4 个答案:

答案 0 :(得分:2)

根据你的语法,我现在要假设SQL Server。

BOL开始,内联函数的语法应为......

--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 [ ) ]
[ ; ]

使用此格式, 无法 使用SET, DECLARE, IF, etc。您可以使用的只是一个SQL语句。 [如果您需要使用程序流程,请查看多语句表值函数。]

这是一个单独的主题,但内联表值函数与其多语句等效项相比具有许多性能效率。几乎总是,如果你能做到内联,你应该这样做。

实际上,您可以在没有IF语句的情况下编写逻辑,并且只使用一个SQL语句。这给出了以下内联表值函数...

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

UNION ALL结合WHERE条款有效地为您执行IF语句。 (请注意,如果user.isTrade可以为NULL,则需要将user.isTrade <> 1更改为更像ISNULL(user.isTrade, 0) <> 1的内容。)

潜在地,您甚至可以将其简化为单个查询,但我会测试它以确定它是否实际上更高效...

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
  • 如果group_id为NULL,则第一次连接将永远不会成功。
  • 然后由OR模拟两个IF块。

答案 1 :(得分:1)

您可以将PROC的结果存储在临时表中:

INSERT INTO #temptbl EXEC [dbo].GetHerdByUserProc(80)

答案 2 :(得分:1)

您需要在定义中定义表的结构,然后将值插入声明表变量...

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

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

答案 3 :(得分:0)

您可以使用CASE语句简单地编写SQL查询。 CASE语句是处理条件查询的最简单方法。

 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