Вообще говоря, функция NEWID () генерирует уникальное значение для каждой строки, когда мы помещаем его в виде столбца в списке выбора:
select
NEWID() as column_name
from table
Существует распространенная, хорошо известная проблема с странное поведение функции NEWID () . Таким образом, мы фактически не можем заставить оптимизатор запросов материализовать значение NEWID () внутри предложения:
select
t.*,
t2.col
from table t
cross join (select NEWID() as col) t2
В этом случае мы снова получаем одинаковые уникальные значения для каждой строки.
Тем не менее, мы должны найти способ заставить оптимизатор вычислять значение NEWID () внутри предложения from. Как мы знаем из логическая обработка запроса , оператор «ORDER» выполняется почти в конце запроса, после предложения SELECT. Нам нужно знать значения, прежде чем мы захотим их отсортировать.
Итак, сначала мы должны как-то отсортировать оператор "select" внутри запроса по значению NEWID (). Единственная легальная возможность сделать это - добавить оператор TOP 1.
Во-вторых, чтобы оптимизатор не пропустил упорядочение только из-за значения 1, мы добавляем еще одно значение NEWID ().
Итак, к каждому выбранному объединению мы должны добавить:
cross join (select top 1 t.group_id from (values (NEWID()), (NEWID()))as t(group_id) ORDER BY group_id) as tt
В этом случае оптимизатор должен, несмотря ни на что, сортировать значения, которые он должен знать заранее.
И запрос выглядит так:
select
[Name],
[Value],
[Group]
from (
select
[Name],
[Value],
tt.group_id as [Group]
from (
values
('abc', '1qwert'),
('def', '1yuiop')
) as T ([Name], [Value])
cross join (select top 1 t.group_id from (values (NEWID()), (NEWID()))as t(group_id) ORDER BY group_id) as tt
union all
select
[Name],
[Value],
tt.group_id as [Group]
from (
values
('abc', '2asdfg'),
('def', '2hjkl')
) as T ([Name], [Value])
cross join (select top 1 t.group_id from (values (NEWID()), (NEWID()))as t(group_id) ORDER BY group_id) as tt
union all
select
[Name],
[Value],
tt.group_id as [Group]
from (
values
('abc', '3zxcv'),
('def', '3bnm')
) as T ([Name], [Value])
cross join (select top 1 t.group_id from (values (NEWID()), (NEWID()))as t(group_id) ORDER BY group_id) as tt
) as t
В этом случае мы не должны материализовать случайные уникальные значения в таблице.
И окончательное исправление заключается в добавлении
select top 1 t.group_id from (values (NEWID()), (NEWID()))as t(group_id) ORDER BY group_id
в CTE.
Окончательный запрос будет выглядеть так:
;with unique_group as (
select top 1
t.group_id
from (values
(NEWID()),
(NEWID())
)as t(group_id)
order by group_id
)
select
[Name],
[Value],
[Group]
from (
select
[Name],
[Value],
tt.group_id as [Group]
from (
values
('abc', '1qwert'),
('def', '1yuiop')
) as T ([Name], [Value])
cross join unique_group as tt
union all
select
[Name],
[Value],
tt.group_id as [Group]
from (
values
('abc', '2asdfg'),
('def', '2hjkl')
) as T ([Name], [Value])
cross join unique_group as tt
union all
select
[Name],
[Value],
tt.group_id as [Group]
from (
values
('abc', '3zxcv'),
('def', '3bnm')
) as T ([Name], [Value])
cross join unique_group as tt
) as t