powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / чудеса при строковой аггрегации, если сдобрить функцией и посыпать сортировкой
8 сообщений из 8, страница 1 из 1
чудеса при строковой аггрегации, если сдобрить функцией и посыпать сортировкой
    #39997491
б-с
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Всем доброго времени суток. Это не ХЕЛПМИ!!!, но просто интересный случай, который я постичь не смог.

@@version:
Код: sql
1.
2.
3.
4.
Microsoft SQL Server 2016 (SP2-CU6) (KB4488536) - 13.0.5292.0 (X64) 
	Mar 11 2019 23:19:30 
	Copyright (c) Microsoft Corporation
	Developer Edition (64-bit) on Windows Server 2016 Standard 10.0 <X64> (Build 14393: ) (Hypervisor)




Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
drop table if exists myTable
GO
CREATE TABLE [dbo].[myTable](
	[myChar2] [char](2) NOT NULL,
	[myId] [int] NOT NULL,
	[myFk] [int] NOT NULL,
	[myDayId] [int] NOT NULL,
	[sbor_1] [numeric](16, 2) NOT NULL,
	[sbor_2] [numeric](16, 2) NOT NULL,
	[sbor_3] [numeric](16, 2) NOT NULL,
 CONSTRAINT [PK_myTable] PRIMARY KEY CLUSTERED 
(
	[myDayId] ASC,
	[myId] ASC,
	[myFk] ASC,
	[myChar2] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

CREATE  or alter FUNCTION [dbo].myFunc(
	  @name		varchar(256)	
	  ,@value	sql_variant
)
returns varchar(8000)
as
begin
	return ',' + @name
end
GO

-- заполняем 1000 записями: [myId] от 1 до 500, по двум [myDayId]
;with cteDay([myDayId]) as(select 1 union select 2)
	,cte([myFk],[myChar2]) as (select 1,'aa')
	,cte1_5(i) as (  select 0 union select 1 union select 2 union select 3 union select 4)
	, cte_id([myId]) as (select 1
							union all
							select [myId]+1 from cte_id
							where [myId] < 100
						)
insert [myTable]
select [myChar2], [myId]+i*100, [myFk], [myDayId], 1,1,1
	from cteDay
	cross join cte
	cross join cte_id
	cross join cte1_5 
order by 2
	;



А теперь пытаемся собрать строку (в оригинале громоздкий Expression, я подобрал упрощенный, с теми же симптомами).
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
declare @reply varchar(max) = ''
             ,@reply2 varchar(max) = ''

select @reply += [dbo].myFunc([myId],[myId])
  --, @reply2 += [dbo].myFunc(sbor_type,[myId])
    from
    (    select
             [myTable].[myId]
            , sbor_1    = sum(sbor_1)
            , sbor_2    = sum(sbor_2)
            , sbor_3    = sum(sbor_3)
         from
            [myTable]
        group by [myId]
    ) sbor
          unpivot (
            sbor_sum for sbor_type in (
                  sbor_1
                , sbor_2
                , sbor_3
                )
            ) as unpv
    order by
          sbor_type,
         [myId]
    option (recompile)

print( @reply)
print( @reply2)




Результат: только последняя запись (нет аггрегации)

А теперь делаем:
- либо раскомментируем строку с ,@reply2+=
- либо закомментируем sbor_type в сортировке
- либо выбираем с top(1000)
- либо в @reply += [dbo].myFunc([myId],[myId]) вместо первого из параметров myId передаем что угодно: 1, 'qq', 'qq'+str([myId]), sbor_type......
- и даже либо собираем и @reply, и @reply2 оба как += [dbo].myFunc([myId],[myId])
Результат: есть аггрегация.

А теперь вернем все как было, и уже вместо второго параметра myId передаем 'qq'+ str([myId]))
Результат: нет аггрегации .
А теперь к такой первой строке раскомментируем второю и играемся.
- , @reply2 += [dbo].myFunc(sbor_type,[myId]) - нет аггрегации
- , @reply2 += [dbo].myFunc([myId],[myId]) - нет аггрегации
- , @reply2 += [dbo].myFunc([myId],sbor_type) - есть аггрегация


План "хороших" выборок:
сначала Sort, потом Compute Scalar
...
Рейтинг: 0 / 0
чудеса при строковой аггрегации, если сдобрить функцией и посыпать сортировкой
    #39997492
б-с
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Виноват, не та фотка.
Вот хороший план )
сначала Sort, потом Compute Scalar
...
Рейтинг: 0 / 0
чудеса при строковой аггрегации, если сдобрить функцией и посыпать сортировкой
    #39997493
б-с
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А вот "плохой" - где аггрегации не добились - в нем Compute Scalar вылезло вперед
...
Рейтинг: 0 / 0
чудеса при строковой аггрегации, если сдобрить функцией и посыпать сортировкой
    #39997495
б-с
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В общем, плохо понимаемое поведение, почему меняется порядок блоков, и почему это влияет на наличие/отсутствие суммирования строк, и как всем этим управлять, чтобы не получать сюрпризов.

Что в итоге сделали: убрали сортировку по sbor_type. Оказалось допустимо.
Но если бы она была жестко нужна (в оригинале sbor_type входит в Expression) - то тупик....

Пользуясь случаем, передаю всем привет, желаю крепкого здоровья, ну и ссылка тут в FAQ битая на майкрософт, там где !NB:
https://www.sql.ru/faq/faq_topic.aspx?fid=130
...
Рейтинг: 0 / 0
чудеса при строковой аггрегации, если сдобрить функцией и посыпать сортировкой
    #39997498
Гавриленко Сергей Алексеевич
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Как сочетаются "Microsoft SQL Server 2016" и "CREATE or alter"?
Зачем здесь эта смешная функция?
Что будет, если применить какой-нибудь другой способ клеить строки (коими FAQ несколько исписан)?
...
Рейтинг: 0 / 0
чудеса при строковой аггрегации, если сдобрить функцией и посыпать сортировкой
    #39997499
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Это тысячелетний баян - https://www.betaarchive.com/wiki/index.php/Microsoft_KB_Archive/287515 ...

Оптимизатор волен размещать Compute Scalar там, где сочтет правильным.
И никакой агрегации на самом деле нет. А есть побочный эффект документированного поведения https://docs.microsoft.com/ru-ru/sql/t-sql/language-elements/select-local-variable-transact-sql?view=sql-server-ver15 SELECT @local_variable обычно используется для возвращения одиночного значения в переменную. Однако, если аргумент expression является именем столбца, может вернуться несколько значений. Если инструкция SELECT возвращает более одного значения, переменной присваивается последнее возвращенное значение.
Сформулировано слегка неверно. На самом деле должно быть так - если инструкция SELECT возвращает более одного значения, переменной последовательно присваиваются значения из каждой возвращаемой строки.
Именно на этом эффекте основана такая "агрегация" и именно поэтому она не работает, когда правая часть выражения вычисляется вне SELECT.

До 2017-го сервера агрегировать строки с гарантированным результатом нужно через for xml path. Или написав CLR-агрегат
Ну или можете поизвращаться
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
with t as
(
    select
             [myTable].[myId]
            , sbor_1    = sum(sbor_1)
            , sbor_2    = sum(sbor_2)
            , sbor_3    = sum(sbor_3)
         from
            [myTable]
        group by [myId]
    ) sbor
          unpivot (
            sbor_sum for sbor_type in (
                  sbor_1
                , sbor_2
                , sbor_3
                )
            ) as unpv
)
select @reply += [dbo].myFunc([myId],[myId])
  --, @reply2 += [dbo].myFunc(sbor_type,[myId])
    from
     (select top (cast(0x7fffffff)) [myId] from t order by sbor_type, [myId]) a
    option (recompile)
...
Рейтинг: 0 / 0
чудеса при строковой аггрегации, если сдобрить функцией и посыпать сортировкой
    #39997504
б-с
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Спасибо за отклики.

>> Как сочетаются "Microsoft SQL Server 2016" и "CREATE or alter"?
В целом, идиллически.
>> Зачем здесь эта смешная функция?
На ее месте могла быть не смешная. Она здесь затем, что симптомы прослеживаются при использовании udf. Из уважения к почтенной публике, не стал выкладывать оригинал - подобрал замену попроще.
>> Что будет, если применить какой-нибудь другой способ клеить строки (коими FAQ несколько исписан)?
Безусловно, можно подобрать рабочий вариант. FOR XML, или с выгрузкой в #промежуточную. Я не ставил это под сомнение.

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

Чем-то же должно объясняться (помимо "именно поэтому!"), то, что
не склеивает:
select @reply += [dbo].myFunc([myId],[myId])
но склеивает оно же, написанное дважды:
select @reply += [dbo].myFunc([myId],[myId])
, @reply2 += [dbo].myFunc([myId],[myId])
...
Рейтинг: 0 / 0
чудеса при строковой аггрегации, если сдобрить функцией и посыпать сортировкой
    #39997506
Гавриленко Сергей Алексеевич
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
б-сВ целом, идиллически.Правильно, оказывается, писать "В целом, идиллически [начиная с 2016 SP1]".

б-сЧем-то же должно объясняться (помимо "именно поэтому!")Объясняется тем, что "и не должно было, а там где работало как хочется, выходила чистая случайность".
...
Рейтинг: 0 / 0
8 сообщений из 8, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / чудеса при строковой аггрегации, если сдобрить функцией и посыпать сортировкой
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]