从另一个select中调用带有表param的标量函数

时间:2018-06-05 18:17:08

标签: sql sql-server sql-server-2008 tsql

我正在使用SQL Server 2008。

我有一个名为fn_takeTableArg的自定义函数,我需要能够像这样使用它:

 select dbo.fn_takeTableArg(<a union of multiple selects>) as MyField from MyTable

自定义表格arg是:

 CREATE TYPE [dbo].[TableArg] AS TABLE(
  Value VARCHAR(2000),
  RepOrApp CHAR
  SortOrder INT
  )

功能类似于:

CREATE FUNCTION dbo.fn_takeTableArg
(
  @t [dbo].[TableArg] READONLY
)
RETURNS VARCHAR(max)
AS
     ... Do something over the passed in table with a with clause, etc.

但是,似乎无法做到这一点,因为我得到“当子查询未引入EXISTS时,只能在选择列表中指定一个表达式。”错误。

大概是因为我应该首先创建一个临时表变量然后用该变量调用我的函数?

但是,我不能这样做,因为我必须从另一个选择内部调用此函数。

2 个答案:

答案 0 :(得分:1)

我真的怀疑,您的方法是您可以选择的最佳方法,但要回答您的问题:您必须首先填写类型化参数,然后将其传递到其中:

USE master;
GO
CREATE DATABASE testdb;
GO
USE testdb;
GO
CREATE TYPE [dbo].[TableArg] AS TABLE(
   [Value] VARCHAR(2000)
  ,RepOrApp CHAR
  ,SortOrder INT
  );
GO
CREATE FUNCTION dbo.fn_takeTableArg
(
  @t [dbo].[TableArg] READONLY
)
RETURNS VARCHAR(max)
AS
BEGIN
RETURN (SELECT TOP 1 [Value] FROM @t);
END
GO

--declare the parameter with your type
DECLARE @TheParameter dbo.TableArg;
--... and fill it
INSERT INTO @TheParameter([Value],RepOrApp,SortOrder)
SELECT o.[name],'x',1 
FROM sys.objects o;

--The parameter is like a table
SELECT * FROM @TheParameter;
--...and can be passed as the funcion's argument
SELECT dbo.fn_takeTableArg(@TheParameter);
GO
USE master;
GO
DROP DATABASE testdb;

更新

刚刚看到你的评论

  

大概是因为我应该首先创建一个临时表变量   然后使用该变量调用我的函数?

     

但是,我不能那样做,因为我必须从里面调用这个函数   另一个选择。

有一个技巧:您可以将SELECT ... FOR XML包装在paranthesis中并处理返回的XML,类似于标量值。

CREATE FUNCTION dbo.fn_takeTableArg
(
  @t XML --You function accepts an XML
)
RETURNS VARCHAR(max)
AS
BEGIN
--do something with the XML, in this case: return the first attribute you find
RETURN @t.value(N'(//@*)[1]','varchar(max)');
END
GO

--The function can take the generic `SELECT` as argument  
--(not really, but the full result-set translated to an XML)
SELECT dbo.fn_takeTableArg(
                            (
                              SELECT [name]
                                    ,'x' AS RepOrApp
                                    ,1 AS SortOrder 
                              FROM sys.objects
                              FOR XML AUTO)
                            );
GO

在函数中,XML看起来像这样:

<sys.objects name="sysrscols" RepOrApp="x" SortOrder="1" />
<sys.objects name="sysrowsets" RepOrApp="x" SortOrder="1" />
<sys.objects name="sysclones" RepOrApp="x" SortOrder="1" />
...

可以使用您选择的别名控制所有命名('sys.objects','name'等)。

备注

标量函数的性能不佳。处理XML的标量函数(必须为每行和任何行创建)将非常缓慢......有更好的方法可以... ...

答案 1 :(得分:0)

您可以将scalar function中的值传递为

select dbo.fn_takeTableArg(t.col) as MyField 
from (<a union of multiple selects>) t;