Как сделать функцию в SQL Server, которая принимает столбец данных? - PullRequest
2 голосов
/ 07 мая 2010

В начале этой недели я сделал следующую функцию в SQL Server 2008, которая принимает два параметра и использует их для выбора столбца «подробных» записей и возвращает их в виде единого списка значений, разделенных запятыми. Теперь, когда я подумаю об этом, я хотел бы взять эту таблицу и специфичную для приложения функцию и сделать ее более общей.

Я не очень разбираюсь в определении функций SQL, так как это мой первый шаг. Как я могу изменить эту функцию, чтобы она принимала данные из одного столбца, чтобы я мог использовать ее более общим способом?

Вместо звонка:

SELECT ejc_concatFormDetails(formuid, categoryName)

Я бы хотел заставить его работать так:

SELECT concatColumnValues(SELECT someColumn FROM SomeTable)

Вот мое определение функции:

FUNCTION [DNet].[ejc_concatFormDetails](@formuid AS int, @category as VARCHAR(75))
RETURNS VARCHAR(1000) AS
BEGIN
 DECLARE @returnData VARCHAR(1000)
 DECLARE @currentData VARCHAR(75)
 DECLARE dataCursor CURSOR FAST_FORWARD FOR
  SELECT data FROM DNet.ejc_FormDetails WHERE formuid = @formuid AND category = @category

 SET @returnData = ''

 OPEN dataCursor

 FETCH NEXT FROM dataCursor INTO @currentData
 WHILE (@@FETCH_STATUS = 0)
 BEGIN
  SET @returnData = @returnData + ', ' + @currentData
  FETCH NEXT FROM dataCursor INTO @currentData
 END

 CLOSE dataCursor
 DEALLOCATE dataCursor

 RETURN SUBSTRING(@returnData,3,1000)
END

Как видите, я выбираю данные столбца в своей функции, а затем перебираю результаты с помощью курсора, чтобы построить мой разделенный запятыми varchar.

Как я могу изменить это, чтобы принять один параметр, который является набором результатов, а затем получить доступ к этому набору результатов с помощью курсора?

Ответы [ 4 ]

5 голосов
/ 07 мая 2010

Другие ответили на ваш главный вопрос - но позвольте мне указать на еще одну проблему с вашей функцией - ужасное использование КУРСОРА!

Вы можете легко переписать эту функцию без использования курсора, без цикла WHILE - ничего подобного. Это будет намного быстрее и намного проще - намного меньше кода:

FUNCTION DNet.ejc_concatFormDetails
            (@formuid AS int, @category as VARCHAR(75))
RETURNS VARCHAR(1000) 
AS
    RETURN 
      SUBSTRING(
        (SELECT ', ' + data
         FROM DNet.ejc_FormDetails 
         WHERE formuid = @formuid AND category = @category
         FOR XML PATH('')
        ), 3, 1000)

Хитрость в том, чтобы использовать FOR XML PATH('') - это возвращает объединенный список ваших data столбцов и фиксированных ', ' разделителей. Добавьте SUBSTRING() на этом, и все готово! Как бы просто это ни было ... нет упрямо-медленных CURSOR, никаких беспорядочных конкатенаций и всего этого тупого кода - всего лишь одно утверждение, и это все, что есть.

2 голосов
/ 07 мая 2010

Вы можете использовать Таблица значений параметров начиная с SQL Server 2008, что позволит вам передавать переменную TABLE в качестве параметра. Ограничения и примеры для этого все в этой статье.

Тем не менее, я бы также отметил, что использование курсора может повредить производительности. Вам не нужно использовать курсор, так как вы можете сделать все это в 1 операторе SELECT:

SELECT @MyCSVString = COALESCE(@MyCSVString + ', ', '') + data 
FROM DNet.ejc_FormDetails 
WHERE formuid = @formuid AND category = @category

Нет необходимости в курсоре

2 голосов
/ 07 мая 2010

Вы можете использовать табличные параметры:

CREATE FUNCTION MyFunction(
    @Data AS TABLE (
        Column1 int,
        Column2 nvarchar(50),
        Column3 datetime
    )
)
RETURNS NVARCHAR(MAX)
AS BEGIN
    /* here you can do what you want */
END
0 голосов
/ 07 мая 2010

Ваш вопрос немного неясен. В вашем первом операторе SQL похоже, что вы пытаетесь передать столбцы в функцию, но нет предложения WHERE. Во втором операторе SQL вы передаете коллекцию строк (результат SELECT). Можете ли вы предоставить некоторые образцы данных и ожидаемый результат?

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

...