【问题标题】:How to create this special counter on a specific value in T-SQL?如何在 T-SQL 中为特定值创建此特殊计数器?
【发布时间】:2017-05-25 08:14:20
【问题描述】:

我遇到了几个小时以来一直在努力解决的问题。 我正在尝试在临时表的列上创建一个特殊计数器,我的表有很多列,其中之一是 col1:

col1 |
######
X    | 
X    | 
A    | 
B    | 
X    | 
C    | 
X    | 
D    | 

特殊计数器应该是这样的:

col1 | counter
###############
X    | 1
X    | 2
A    | 2
B    | 2
X    | 3
C    | 3
X    | 4
D    | 4

它应该只计算“X”值,并保持不变,以防该值是其他值。

我尝试了很多东西,我得到的最接近的方法是创建另一个只有计数器的临时表,然后将它与原始表连接起来,但结果是这样的:

col1 | counter
###############
X    | 1
X    | 2
A    | NULL
B    | NULL
X    | 3
C    | NULL
X    | 4
D    | NULL

那么,我该如何创建这个特殊的计数器?

【问题讨论】:

  • 您按哪一栏排序?什么版本的 SQL Server?
  • @DanField,临时表中还有一个 SortOrder 列,我用它来排序值,但问题中没有显示。

标签: sql sql-server tsql count counter


【解决方案1】:

有更简单和直接的解决方案。我们只需要一点观察:计数器等于前几行中Xs 的计数:

select id, 
       col1,
       (select count(*) from @t where id <= t.id and col1 = 'X') as counter
from @t t

【讨论】:

    【解决方案2】:

    CASE 中的Row_Number() 应该可以解决问题。

    您会注意到我添加了一个字段 ID 来维护一个序列。

    Declare @YourTable table (ID int,col1 varchar(25))
    Insert Into @YourTable values
    (1,'X'),
    (2,'X'),
    (3,'A'),
    (4,'B'),
    (5,'X'),
    (6,'C'),
    (7,'X'),
    (8,'D')
    
    Select ID,Col1
          ,Counter = max(counter) over (Order By ID)
     From (
           Select ID
                 ,col1
                 ,counter = case when col1='X' then row_number() over (Partition By col1 Order by ID) else null end
            From  @YourTable
          ) A
     Order By ID
    

    返回

    ID  Col1    Counter
    1   X       1
    2   X       2
    3   A       2
    4   B       2
    5   X       3
    6   C       3
    7   X       4
    8   D       4
    

    【讨论】:

    • 其实我在问题中提到我不想要NULL值,请看最后一个结果表,在这种情况下计数器应该保持不变。
    • @AbeerSul 误读了这个问题。我会再戳它
    • @AbeerSul 是否有另一列包含该序列?
    • 您能解释一下这是如何工作的吗?没看懂
    • @AbeerSul 子查询中的计数器将为 X 生成一个 row_number()。然后 max(counter) 是另一个窗口函数。它将从当前行和前一行中获取最大 X-Counter。窗口函数是你的朋友。非常值得您花时间适应它们,
    【解决方案3】:

    这里是更新语句。每次遇到 X 时,该语句都会增加变量,并使用正确的值更新每一行。

    declare @counter int = 0;
    update   #temp
    set      counter = @counter
           , @counter += case when col1 = 'X' then 1
                              else 0
                         end;
    

    【讨论】:

    • 我不知道您可以在更新的集合部分更新标量和列。酷。
    • 我唯一要补充的是,这可能不会按照 OP 想要的方式使用排序列进行排序......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-14
    • 2023-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-20
    相关资源
    最近更新 更多