4

我在尝试从 SQL 函数返回表时遇到一些问题,其中创建表的 SQL 是动态编写的。

到目前为止,我有:

CREATE FUNCTION dbo.SEL_PCD
(
    @COBDate AS DATETIME,
    @FileName AS VARCHAR(50),
    @PC AS VARCHAR(50),
    @MyList AS VARCHAR(max),

    DECLARE @SQL VARCHAR(max)

    SET @SQL = 'SELECT * FROM 
                    (SELECT tab1.TID FROM
                        (SELECT TID FROM dbo.SEL_RT('+@COBDate+','+@FileName+') WHERE BID IN ('+ @MyList +')) tab1
                    JOIN
                        (SELECT TID FROM CT WHERE (Col_Name LIKE %' + @PC + '% OR Bk LIKE %' + @PC + '%) AND FileName = ' + @FileName + ' AND COBDate = @COBDate) tab2
                    ON tab1.TID = tab2.TID) tab3
                JOIN
                    (SELECT TID, Value FROM CR WHERE BID IN (' + @MyList + ') AND COBDate = ' + @COBDate + ' AND FileName = ' + @FileName + 'AND ScenID = 266) tab7
                ON tab3.TID = tab7.TID'

)
RETURNS TABLE AS
RETURN
(
    EXEC sp_executesql @SQL
)
GO

我在声明 SQL 变量时遇到错误。我可以通过执行命令返回表吗?

4

3 回答 3

3

您不能从函数内调用存储过程,包括存储过程EXECUTESP_EXECUTESQL. 这意味着您不能在函数中嵌入动态 sql。


不能调用存储过程的原因是因为函数不允许有副作用(调用它们本身不能更改任何数据——它们不能插入、更新或删除)。但是存储过程可以。这意味着调用存储过程的函数将突然变得能够产生副作用。

SP 可以调用函数,而不是相反。


此外,SQL 被编译为执行计划。那时正在使用的表和索引都变得固定。如果一个函数包含可能的动态 sql;要使用的表等在编译时是未知的,SQL 没有这种能力。


在您的情况下,您的查询中似乎需要动态 SQL 的唯一部分是您将逗号分隔的列表作为 @myList 参数传递。但是,还有另一种方法。

寻找dbo.fn_split()在线可用的众多功能之一(以及许多在线功能)。然后使用该功能加入数据...

CREATE FUNCTION dbo.SEL_PCD( @COBDate     AS DATETIME,
                             @FileName    AS VARCHAR(50),
                             @PC          AS VARCHAR(50),
                             @MyList      AS VARCHAR(max)
                            )
RETURNS TABLE
AS
RETURN
  SELECT
    CR.TID,
    CR.Value
  FROM
    dbo.SEL_RT(@COBDate, @FileName) AS RT
  INNER JOIN
    CT
     ON CT.TID = RT.TID
  INNER JOIN
    CR
     ON CR.TID = RT.TID
  WHERE
    (CT.Col_Name LIKE '%'+@PC+'%' OR CT.Bk LIKE '%'+@PC+'%')
    AND CT.FileName = @FileName
    AND CT.COBDate  = @COBDate
    AND CR.FileName = @FileName
    AND CR.COBDate  = @COBDate
    AND CR.ScenID   = 266
    AND RT.BID IN (SELECT id FROM dbo.fn_split(@myList, ',') AS my_list)
    AND CR.BID IN (SELECT id FROM dbo.fn_split(@myList, ',') AS my_list)
于 2012-06-28T11:26:36.290 回答
3

试试这个:

CREATE PROCEDURE dbo.SEL_PCD
(
    @COBDate DATETIME,
    @FileName VARCHAR(50),
    @PC VARCHAR(50),
    @MyList VARCHAR(max)
) AS

    DECLARE @SQL VARCHAR(max)

    SELECT @SQL = 'SELECT * FROM 
                    (SELECT tab1.TID FROM
                        (SELECT TID FROM dbo.SEL_RT('+@COBDate+','+@FileName+') WHERE BID IN ('+ @MyList +')) tab1
                    JOIN
                        (SELECT TID FROM CT WHERE (Col_Name LIKE %' + @PC + '% OR Bk LIKE %' + @PC + '%) AND FileName = ' + @FileName + ' AND COBDate = @COBDate) tab2
                    ON tab1.TID = tab2.TID) tab3
                JOIN
                    (SELECT TID, Value FROM CR WHERE BID IN (' + @MyList + ') AND COBDate = ' + @COBDate + ' AND FileName = ' + @FileName + 'AND ScenID = 266) tab7
                ON tab3.TID = tab7.TID'

EXEC(@SQL)

职能

  • 可与 Select 语句一起使用
  • 不返回输出参数但返回表变量
  • 你可以加入UDF
  • 不能用于更改服务器配置
  • 不能与 XML FOR 子句一起使用
  • 函数内不能有事务

存储过程

  • 必须使用 EXEC 或 EXECUTE
  • 返回输出参数
  • 可以创建表但不会返回表变量
  • 你不能加入SP
  • 可用于更改服务器配置
  • 可与 XML FOR 子句一起使用
  • 可以在 SP 内进行交易
于 2012-06-28T11:30:24.470 回答
0

您不能在函数中使用执行命令

CREATE PROCEDURE dbo.SEL_PCD4
(
    @COBDate AS DATETIME,
    @FileName AS VARCHAR(50),
    @PC AS VARCHAR(50),
    @MyList AS VARCHAR(max)
) AS
    DECLARE @SQL VARCHAR(max)

    SET @SQL = 'SELECT * FROM 
                    (SELECT tab1.TID FROM
                        (SELECT TID FROM dbo.SEL_RT('+@COBDate+','+@FileName+') WHERE BID IN ('+ @MyList +')) tab1
                    JOIN
                        (SELECT TID FROM CT WHERE (Col_Name LIKE %' + @PC + '% OR Bk LIKE %' + @PC + '%) AND FileName = ' + @FileName + ' AND COBDate = @COBDate) tab2
                    ON tab1.TID = tab2.TID) tab3
                JOIN
                    (SELECT TID, Value FROM CR WHERE BID IN (' + @MyList + ') AND COBDate = ' + @COBDate + ' AND FileName = ' + @FileName + 'AND ScenID = 266) tab7
                ON tab3.TID = tab7.TID'

    EXEC sp_executesql @SQL

于 2012-06-28T11:38:05.710 回答