Создать уникальный идентификатор для групп из объединения - PullRequest
0 голосов
/ 24 марта 2020

Есть ли способ получить уникальный идентификатор для каждой [группы], которая будет генерироваться динамически? Я пробовал newid (), но в результате у каждой строки разные значения. Намерение состоит в том, чтобы не беспокоиться о добавлении уникального значения для каждого набора T (как указано набором, который закомментирован). (Начальный символ для каждого значения [Значение] (например, 1) соответствует жестко заданному значению [Группа] только для удобства чтения при просмотре результатов.)

select
    [Name],
    [Value],
    [Group]
from (
    select
        [Name],
        [Value],
        1 as [Group] --newid() as [Group] --
    from (
        values
            ('abc', '1qwert'),
            ('def', '1yuiop')
        ) as T ([Name], [Value])
    union all
    select
        [Name],
        [Value],
        2 as [Group] --newid() as [Group] --
    from (
        values
            ('abc', '2asdfg'),
            ('def', '2hjkl')
        ) as T ([Name], [Value])
    union all
    select
        [Name],
        [Value],
        3 as [Group] --newid() as [Group] --
    from (
        values
            ('abc', '3zxcv'),
            ('def', '3bnm')
        ) as T ([Name], [Value])
    --union all
    --select
    --  [Name],
    --  [Value],
    --  ? as [Group] --newid() as [Group] --
    --from (
    --  values
    --      ('abc', '?poiuy'),
    --      ('def', '?trewq')
    --  ) as T ([Name], [Value])
    ) as TT
order by
    [Group],
    [Name];

Ответы [ 2 ]

0 голосов
/ 05 апреля 2020

Дайте каждому подзапросу в вашем объединении уникальный ссылочный номер, свяжите это число с небольшим набором значений newid (), которые также имеют одинаковый набор целых чисел.

;with cte as (
    select 1 as gid, newid() as [group]
    union all
    select gid + 1,  newid() 
    from cte
    where gid < 3
    )
select
    [Name],[Value],[Group] 
from (
    select
        [Name],[Value],        1 as gid
    from (
        values
            ('abc', '1qwert'),
            ('def', '1yuiop')
        ) as T ([Name], [Value])
    union all
    select
        [Name],[Value],        2 as gid
    from (
        values
            ('abc', '2asdfg'),
            ('def', '2hjkl')
        ) as T ([Name], [Value])
    union all
    select
        [Name], [Value],      3 as gid
    from (
        values
            ('abc', '3zxcv'),
            ('def', '3bnm')
        ) as T ([Name], [Value])
   ) d
inner join cte on d.gid = cte.gid  

см. https://rextester.com/IEPJC57700

+----+------+--------+--------------------------------------+
|    | Name | Value  |                Group                 |
+----+------+--------+--------------------------------------+
|  1 | abc  | 1qwert | 68f1884f-c3af-44b6-9856-2ca71615e4aa |
|  2 | def  | 1yuiop | 68f1884f-c3af-44b6-9856-2ca71615e4aa |
|  3 | abc  | 2asdfg | bf36a235-ef68-4c02-a502-8ba0009aa302 |
|  4 | def  | 2hjkl  | bf36a235-ef68-4c02-a502-8ba0009aa302 |
|  5 | abc  | 3zxcv  | 221ca4d2-ed7f-4654-9234-7081360f693c |
|  6 | def  | 3bnm   | 221ca4d2-ed7f-4654-9234-7081360f693c |
+----+------+--------+--------------------------------------+  
0 голосов
/ 04 апреля 2020

Вообще говоря, функция 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
...