根据行顺序获取计数

har*_*ded 3 sql-server sql-server-2016

我有一个这种结构的表

Create Table Example (
[order] INT,
[typeID] INT
)
Run Code Online (Sandbox Code Playgroud)

有了这些数据:

order|type
1   7
2   11
3   11
4   18
5   5
6   19
7   5
8   5
9   3
10  11
11  11
12  3
Run Code Online (Sandbox Code Playgroud)

我需要根据订单获取每种类型的计数,例如:

type|count
7      1
11     **2**
18     1
5      1
19     1
5      **2**
3      1
11     **2**
3      1
Run Code Online (Sandbox Code Playgroud)

上下文

让我们说这张桌子是关于房子的,所以我在订单中有一个清单.所以我有

  • 订单1:红房子
  • 2:白宫
  • 3:白宫
  • 4:红房子
  • 5:一幢蓝房子
  • 6:一座蓝色的房子
  • 7:白宫

所以我需要显示信息浓缩.我需要说:

  • 我有1个红房子
  • 然后我有2个白色的房子
  • 然后我有一个红房子
  • 然后我有2个蓝房子
  • 然后我有1个白宫

因此,计数基于订单.该DENSE_RANK函数将帮助我,如果我能够在RANK重新分区更改时.

Xed*_*dni 5

所以我有一个答案,但我必须警告你,由于它是如何完成的,它可能会引起一些焦虑.它使用了一种称为" 古怪的更新 "的东西.如果你计划实现这一点,请通过链接文章阅读上帝的爱,并了解这是一个"无证件的黑客",需要精确实施,以避免意外的后果.

如果你有一点点数据,我只是为了简单和清晰而痛苦地排着行.但是,如果您有大量数据并且仍需要高性能,则可能会这样做.

要求

  1. 表必须按照要进行的顺序具有聚簇索引
  2. 表必须没有其他索引(这些索引可能会导致SQL从另一个索引中读取数据,该索引的顺序不正确,导致行顺序的量子叠加崩溃).
  3. 在操作期间必须完全锁定表(tablockx)
  4. 更新必须以串行方式进行(maxdop 1)

它能做什么

你知道人们怎么告诉你表中的数据没有隐含的顺序吗?这仍然是99%的时间.除了我们知道最终它必须以某种顺序存储在磁盘上.这就是我们在这里利用的顺序.通过强制进行聚簇索引更新以及可以在更新列的同一更新语句中分配变量这一事实,您可以快速有效地滚动数据.

我们设置数据:

if object_id('tempdb.dbo.#t') is not null drop table #t
create table #t
(
    _order int primary key clustered,
    _type int,
    _grp int
)

insert into #t (_order, _type)
select 1,7
union all select 2,11
union all select 3,11
union all select 4,18
union all select 5,5
union all select 6,19
union all select 7,5
union all select 8,5
union all select 9,3
union all select 10,11
union all select 11,11
union all select 12,3
Run Code Online (Sandbox Code Playgroud)

这是更新声明.我将介绍下面的每个组件

declare @Order int, @Type int, @Grp int

update #t with (tablockx)
set @Order = _order,
    @Grp = case when _order = 1 then 1
                when _type != @Type then @grp + 1
                else @Grp
           end,
    @Type = _type,
    _grp = @Grp
option (maxdop 1)
Run Code Online (Sandbox Code Playgroud)
  1. 使用执行更新(tablockx).如果你正在使用临时表,你知道桌面上没有争用,但仍然是一个很好的习惯(如果使用这种方法甚至可以被认为是一个很好的习惯).
  2. 设置@Order = _order.这看起来像一个毫无意义的陈述,它有点像.但是,由于它_order是表的主键,因此将其分配给变量是强制SQL执行聚簇索引更新的原因,这对于此工作至关重要
  3. 填充整数以表示所需的顺序组.这就是魔术发生的地方,你必须考虑它在滚动表格方面.当_order为1(第一行)时,只需将@Grp变量设置为1.如果在任何给定行上,列值_type与变量值不同@type,则增加分组变量.如果值相同,我们只需坚持@Grp上一行中的值.
  4. @Type使用列_type的值更新变量.注意这个HAS在分配之后@Grp才能获得正确的值.
  5. 最后,设置_grp = @Grp.这是使用步骤3的结果更新实际列值的位置.
  6. 所有这一切都必须完成option (maxdop 1).这意味着最大并行度设置为1.换句话说,SQL不能执行任何可能导致排序关闭的任务并行化.

现在只是在_grp现场分组的问题._grp每个连续批次都有一个唯一的值_type.

结论

如果这看起来香蕉和hacky,它是.就像所有事情一样,你需要花一点时间,如果你计划实施它,我建议你真正使用这个概念来完全理解它,因为我保证没有其他人会知道如何解决它如果你在半夜接到一个电话,它就会破裂.

  • 奇怪的更新是我非常熟悉的.您通过发布Jeff Moden的文章链接做得很好. (3认同)
  • 虽然我认为,这是*用链锯切割面包*:-D答案很棒并且显示出非常深刻的洞察力.+1来自我的身边! (2认同)