为 union 中的组创建唯一标识符

Create a unique identifier for groups from union

有没有办法为每个要动态生成的[群组]获取唯一ID?我试过 newid() 但结果是每行的值不同。目的是不必担心为每个 T 集添加唯一值(如注释掉的集所示)。 ([Value] 的每个值(例如 1)的初始字符对应于 [Group] 的硬编码值,仅用于查看结果时的可读性目的。)

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];

一般来说,函数 NEWID() 为每一行生成唯一值,当我们将它作为列放在 select 列表中时:

  select
    NEWID() as column_name
  from table

函数的奇怪行为存在一个众所周知的常见问题 NEWID()。 所以我们实际上不能强制查询优化器从子句中实现 NEWID() 值:

select
t.*,
t2.col
from table t
cross join (select NEWID() as col) t2

在这种情况下,我们再次为每一行获得相同的唯一值。

仍然,我们必须找到一种方法来强制优化器计算 from 子句中的 NEWID() 值。 正如我们从 logical query processing 命令中知道的那样,"ORDER" 运算符几乎在查询结束时执行,在 SELECT 子句之后。在我们想要对它们进行排序之前,我们必须知道值。

所以首先,我们应该按 NEWID() 值以某种方式对查询中的 "select" 语句进行排序。 这样做的唯一合法可能性是添加 TOP 1 运算符。

其次,为了确保优化器不会因为只有 1 个值而跳过排序,我们添加了另一个 NEWID() 值。

因此,对于每个联合 select 我们应该添加:

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

在这种情况下,我们不应该在 table.

中具体化随机唯一值

最后的更正是添加

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

为联合中的每个子查询提供一个唯一的参考编号,将该编号与一小组 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 |
+----+------+--------+--------------------------------------+