sql 从一系列位值中生成几何序列

sql make geometric sequence from series of bit values

我有这个table:

declare @Table table (value int)
insert @Table select 0
insert @Table select 1
insert @Table select 1
insert @Table select 1
insert @Table select 0
insert @Table select 1
insert @Table select 1

现在,我需要进行 Select 查询,这将添加一列。一旦列值中有值1的系列,该列将构成一个几何序列。

这将是结果:

好的.. 首先,在数据库中,table 中的数据没有固有的排序。因此,为了做你想做的事,你需要在 sort/order 上创建一个字段。在本例中,我使用的是名为 'SortID'.

的 IDENTITY 字段
CREATE TABLE #Table (SortID int IDENTITY(1,1), BitValue bit);
INSERT INTO #Table (BitValue)
VALUES (0), (1), (1), (1), (0), (1), (1);

这给出了具有以下起始数据的 table

SortID  BitValue
1       0
2       1
3       1
4       1
5       0
6       1
7       1

现在,解决问题

  • 一种方法是通过递归 CTE - 当前行的值基于前几行的值。
  • 但是,递归 CTE 可能存在性能问题(它们基本上是循环),因此最好尽可能采用基于集合的方法。
  • 在这种情况下,因为你想要一个相关行号的2次方的几何序列,我们不需要前面的行来计算这一行——我们只需要知道行号

下面的做法

  • 使用 CTE 创建一个名为 'GroupNum' 的新字段,用于将行分组在一起。每次一行的 BitValue 为 0 时,它都会将 GroupNum 递增 1。
    • 在您的示例中,前四行将具有 GroupNum = 1,其余三行将具有 GroupNum = 2
  • 在上面使用 window 函数 - 按这些组编号进行分区,并在每个组中获得 row_number(减一)。
  • 最终结果设置为变量@a对相关row_number的幂。

为了匹配您的示例,我使用 @a = 2 作为 POWER 函数的基础。

DECLARE @a int;
SET @a = 2;

WITH Grouped_BitValues AS
    (SELECT SortID, BitValue, 
            CASE WHEN BitValue = 0 THEN 1 ELSE 0 END AS NewGrpFlag,
            SUM(CASE WHEN BitValue = 0 THEN 1 ELSE 0 END) OVER (ORDER BY SortID) AS GroupNum            
    FROM    #Table
    )
SELECT  BitValue, POWER(@a, ROW_NUMBER() OVER (PARTITION BY GroupNum ORDER BY SortID) -1) AS Geometric_Sequence
FROM Grouped_BitValues
ORDER BY SortID;

这是结果

BitValue  Geometric_Sequence
0         1
1         2
1         4
1         8
0         1
1         2
1         4

请注意,在您的问题中,对于正确的几何序列,2^0 应该是 1,而不是 0。相反,如果您想要 0,则需要在 Geometric_Sequence 中编码以获得 CASE 表达式(例如,CASE WHEN BitValue = 0 THEN 0 ELSE POWER(...) AS Geometric_Sequence)。

这里是 db<>fiddle

  • 设置
  • 答案
  • 答案的组成部分(例如,CTE 和计算)以展示其计算方式

我将其表述为一道算术题。首先,您的问题表明行的顺序很重要。因此,您需要一列来指定排序。我假设有一个包含此信息的 id 列。

然后创建序列开始的组,对 0 进行累加和——所有 1 都在同一组中。给定数据,您可以将其表示为 sum(1 - value) over (order by id).

那就用算术吧:

select t.*,
       value * power(2, row_number() over (partition by grp order by id) - 1) as generatedsequence
from (select t.*, sum(1 - value) over (order by id) as grp
      from @table t
     ) t;

Here 是一个 db<>fiddle.

算术是要枚举组中的值,然后对 2 进行该次幂(除非 value0)。所以子查询 returns:

id.    value    grp
1         1      1
2         1      1
3         1      1
4         1      1
5         0      2
6         1      2
7         1      2

然后 row_number() 枚举每个 grp.

中的值