用于检测有序列表中的更改的函数

时间:2010-12-29 12:39:14

标签: sql sql-server tsql sql-server-2008

我喜欢在T-SQL中找到可以找到检测给定列表或记录中的更改的方法的解决方案。

物理表是这样的:

| id |val |
|----|----|
| 1  | A  |
|----|----|
| 2  | A  |
|----|----|
| 3  | B  |
|----|----|
| 4  | B  |
|----|----|
| 5  | A  |
|----|----|
| 6  | A  |
|----|----|

id是一个顺序整数

val是一个任意值

我想添加一个计算字段,可以某种方式表示val

的更改

期望的结果:

| id |val | segment |
|----|----|---------|
| 1  | A  | 1       |
|----|----|---------|
| 2  | A  | 1       |
|----|----|---------|
| 3  | B  | 2       |
|----|----|---------|
| 4  | B  | 2       |
|----|----|---------|
| 5  | A  | 3       |
|----|----|---------|
| 6  | A  | 3       |
|----|----|---------|

我想要做的是按照这样的“细分”进行分组的可能性:

| from_id | to_id | val |
|---------|-------|-----|
|     1   |    2  |  A  |
|     3   |    4  |  B  |
|     5   |    6  |  A  |
|---------|-------|-----|

2 个答案:

答案 0 :(得分:4)

假设SQL Server 2005 +

DECLARE @T TABLE (
id INT PRIMARY KEY,
val CHAR(1))

INSERT INTO @T
SELECT 1,'A' UNION ALL SELECT 2,'A' UNION ALL
SELECT 3,'B' UNION ALL SELECT 4,'B' UNION ALL
SELECT 5,'A' UNION ALL SELECT 6,'A'

;WITH cte1 AS(
SELECT 
      id,
      val, 
      ROW_NUMBER() OVER (ORDER BY id) - ROW_NUMBER() OVER (PARTITION BY val ORDER BY id) AS Grp
FROM @T
),
cte2 AS(
SELECT 
      id,
      val, 
      MIN(id) OVER (PARTITION BY Grp, val) AS GrpStart
FROM cte1
)
SELECT 
      id,
      val, 
      DENSE_RANK() OVER (ORDER BY GrpStart) AS segment 
FROM cte2

或更新的要求更简单

;WITH cte AS(
SELECT 
      id,
      val, 
      ROW_NUMBER() OVER (ORDER BY id) - ROW_NUMBER() OVER (PARTITION BY val ORDER BY id) AS Grp
FROM @T
)
SELECT 
      val, 
      MIN(id) AS from_id,
      MAX(id) AS to_id
FROM cte
GROUP BY Grp, val
ORDER BY from_id

答案 1 :(得分:0)

这可能需要稍微修改才能工作。此外,我从不使用循环,这可能不是最有效的方法。

Declare @counter int

Set @counter = 1

Declare @seg int

Set @seg = 1

Declare @cur varchar(50)

Set @ cur = select val from table where id = 1

While @counter <= select max id from table

Begin

    if(@cur == select val from table where id = @counter)
        update table set segment = @seg where id = @counter
    else
    {
        set @cur = select val from table where id = @counter
        set @ seg = @seg + 1
        update table set segment = @seg where id = @counter
    }
    Set @counter = @counter + 1

End

那就是一般的想法......