SqlServer 2019 использует табличную и скалярную функцию в курсор - PullRequest
0 голосов
/ 17 февраля 2020

У меня произошла странная ошибка:

Сообщение 596, уровень 21, состояние 1, строка 0

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

Кажется, что ошибка генерируется, когда я использую курсор, например:

DECLARE dbCursor CURSOR
            FOR 
                SELECT (SELECT TOP 1 VAL FROM dbo.fn_Table('n:',dbo.[fn_Scalar](var)) ORDER BY VAL) 
                from table

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

Если в Курсор я выполняю только fn_Table ИЛИ fn_Scalar, это нормально.

Если в курсоре я выполняю ОБА функции, у меня есть вышеуказанная ошибка.

В более старых версиях SQL сервера (чем 2019) курсор работает нормально.

Не могли бы вы дать мне идею?

Спасибо.

LE Функции: ALTER function [dbo]. [UrlDecode ] (@ url nvarchar (max)) возвращает nvarchar (max) в качестве начала объявлять @foo datetime = getdate ();

DECLARE @Position INT, @Base CHAR (16), @High TINYINT, @Low TINYINT , @Pattern CHAR (21)

SELECT  @Base = '0123456789abcdef',
    @Pattern = '%[%][0-9a-f][0-9a-f]%',
    @URL = REPLACE(@URL, '+', ' '),
    @Position = PATINDEX(@Pattern, @URL)

WHILE @Position > 0
    SELECT  @High = CHARINDEX(SUBSTRING(@URL, @Position + 1, 1), @Base COLLATE Latin1_General_CI_AS),
        @Low = CHARINDEX(SUBSTRING(@URL, @Position + 2, 1), @Base COLLATE Latin1_General_CI_AS),
        @URL = STUFF(@URL, @Position, 3, CHAR(16 * @High + @Low - 17)),
        @Position = PATINDEX(@Pattern, @URL)

RETURN  @URL

end

ALTER FUNCTION [dbo]. [Split] (@sep VARCHAR (32), @s VARCHAR (MAX))

ВОЗВРАЩАЕТСЯ @T TABL E (val VARCHAR (MAX))

КАК НАЧАТЬ

--declare @foo datetime=getdate();
--Remove separator if the case
IF RIGHT(LTRIM(RTRIM(@s)),1) = @sep 
    SET @s = LEFT(LTRIM(RTRIM(@s)), LEN(LTRIM(RTRIM(@s))) - 1);

DECLARE @xml XML
SET @XML = N'<root><r>' + REPLACE(@s, @sep, '</r><r>') + '</r></root>'

INSERT INTO @t(val)
SELECT r.value('.','VARCHAR(250)') as Item
FROM @xml.nodes('//root/r') AS RECORDS(r)

RETURN

END

И курсор: DECLARE cursor_product КУРСОР ВЫБРАТЬ (ВЫБРАТЬ ТОП-1 ВАЛ ИЗ ОТ dbo. split ('n:', dbo.UrlDecode) ORDER BY VAL) из ABSENTEE

OPEN cursor_product;

ПОЛУЧИТЬ СЛЕДУЮЩИЙ ИЗ cursor_product WHILE @@ FETCH_STATUS = 0 НАЧАТЬ

    FETCH NEXT FROM cursor_product
END;

ЗАКРЫТЬ cursor_product; DEALLOCATE cursor_product;

Пожалуйста, не обращайте внимания на то, как определяется курсор, в любом случае возникает ошибка. Спасибо.

Ответы [ 2 ]

0 голосов
/ 18 февраля 2020

В нынешнем виде вам придется изменить оператор выбора курсора (скалярное udf-inlining было просто слепым предположением [функция + sql2019 не работает, но работает до sql2019], проблема заключается в выполнении курсора):

Опция 1:

The answer of Marc Guillot (populate a table and iterate over that)

Опция 2: APPLY (вызовы функций)

DECLARE cursor_product CURSOR FOR 
select f.VAL
from ABSENTEE as a
cross /*outer ?*/ apply
(
    SELECT TOP 1 VAL 
    FROM dbo.split('n:',dbo.UrlDecode(a.columnXYZ)) 
    ORDER BY VAL
) as f;

Опция 3: агрегирование по таблице ABSENTEE

DECLARE cursor_product CURSOR FOR 
select (SELECT TOP 1 VAL FROM dbo.split('n:',dbo.UrlDecode(columnXYZ)) ORDER BY VAL) 
from ABSENTEE
group by ABSENTEE.columnXYZ, ABSENTEE.othercolumn(s)

Вариант 4: оконная агрегация по результату функции

DECLARE cursor_product CURSOR FOR 
select 
    MIN(
          (SELECT TOP 1 VAL FROM dbo.split('n:',dbo.UrlDecode(columnXYZ)) ORDER BY VAL) 
       ) over(partition by columnXYZ)
from ABSENTEE
0 голосов
/ 17 февраля 2020

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

DECLARE @MyData table (VAL int)

INSERT INTO @MyData (VAL)
       SELECT (SELECT TOP 1 VAL FROM dbo.fn_Table('n:',dbo.[fn_Scalar](var)) ORDER BY VAL) 
       FROM table

DECLARE dbCursor CURSOR FOR SELECT VAL FROM @MyData
...