Вызов скалярной функции с параметром таблицы из другого выбора - PullRequest
0 голосов
/ 05 июня 2018

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

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

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

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

 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 голосов
/ 06 июня 2018

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

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

0 голосов
/ 05 июня 2018

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

select dbo.fn_takeTableArg(t.col) as MyField 
from (<a union of multiple selects>) t;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...