Вызов скалярной функции с параметром table изнутри другого

cooper_milton спросил: 12 мая 2018 в 04:37 в: sql

Я работаю с SQL Server 2008.

У меня есть пользовательская функция fn_takeTableArg, и мне нужно иметь возможность использовать ее следующим образом:

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

Пользовательский аргумент table:

 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". error.

Предположительно, потому что я должен сначала создать переменную таблицы temp, а затем вызвать свою функцию с этой переменной?

Но я не могу этого сделать, потому что мне нужно позвонить эта функция изнутри другого выбирает.

2 ответа

Shnugo ответил: 13 мая 2018 в 09:44

Я действительно сомневаюсь, что ваш подход - это лучшее, что вы можете выбрать, но чтобы ответить на ваш вопрос: сначала вы должны заполнить типизированный параметр, как и любую другую таблицу, и передать его:

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;

UPDATE

Просто увидела ваше замечание

Предположительно, потому что я должен сначала создать переменную таблицы temp, а затем вызвать мою функцию с этой переменной?

Но я не могу этого сделать, потому что мне нужно вызывать эту функцию изнутри другого выбора.

Существует такая хитрость: вы можете обернуть 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, которая должна быть создана для каждой и любой строки, будет очень медленной ... Есть гораздо более эффективные подходы, предположительно ...

cooper_milton ответил: 13 мая 2018 в 05:50
Большой! Благодарю. Я пытался избегать передачи его в качестве XML по основным причинам. Но это работает, так хорошо.
Yogesh Sharma ответил: 12 мая 2018 в 05:32

Вы можете передать значение в scalar function как

select dbo.fn_takeTableArg(t.col) as MyField 
from (<a union of multiple selects>) t;
Shnugo ответил: 13 мая 2018 в 06:08
Я думаю, что OP хочет передать полный результат в функцию, следовательно UDT ...