2

最初,我有两个变量 x(组变量)和 y,现在我想创建第三个变量 z,它在每组 x 中从 1 开始,并在 y 变化时增加 1。请看下面的例子。有人可以帮助我如何在 sql server 2008 中实现它吗?

非常感谢!

x: a a a a a a a a b b b b b b b b
y: 0 0 0 1 0 0 2 3 0 1 0 0 2 3 0 0

最后,我想像这样创建 z :

x: a a a a a a a a b b b b b b b b
y: 0 0 0 1 0 0 2 3 0 1 0 0 2 3 0 0
z: 1 1 1 2 3 3 4 5 1 2 3 3 4 5 6 6
4

4 回答 4

3

您可以使用递归 CTE和类似的row_number东西。

with C1 as
(
  select T1.id,
         T1.x,
         T1.y,
         row_number() over (partition by T1.x order by T1.id) as rn
  from table1 as T1
), C2 as
(
  select C1.id,
         C1.x,
         C1.y,
         C1.rn,
         1 as z
  from C1
  where C1.rn = 1
  union all
  select C1.id,
         C1.x,
         C1.y,
         C1.rn,
         C2.z + case when C1.y <> C2.y then 1 else 0 end
  from C1 
    inner join C2
      on C1.x = C2.x and
         C1.rn = C2.rn + 1
)
select x, y, z
from C2
order by id
option (maxrecursion 0);

请注意,使用 CTE 作为递归查询的源可能会产生一些性能问题。如果是这种情况,我建议您将 CTE 的结果C1放在一个带有主键的临时表中(x, rn)

SQL小提琴

于 2012-08-05T07:57:32.153 回答
1

您不能完全做到这一点,row_number() over (partition by ... order by ...)而且CTE查询似乎也不起作用。我喜欢尽可能避免使用游标,但游标可能适合您的情况:

declare @tbl table (id int, x char(1), y int, z int null)

declare
  @id int, @x char(1), @y int,
  @x2 char(1) = null, @y2 int = null, @z int

insert into @tbl (id, x, y) values
(1, 'a', 0), (2, 'a', 0), (3, 'a', 0),
(4, 'a', 1),
(5, 'a', 0), (6, 'a', 0),
(7, 'a', 2),
(8, 'a', 3),
(9, 'b', 0),
(10, 'b', 1),
(11, 'b', 0), (12, 'b', 0),
(13, 'b', 2),
(14, 'b', 3),
(15, 'b', 0), (16, 'b', 0)

declare cr cursor for
  select id, x, y
  from   @tbl
  order by  id

open cr
fetch next from cr into @id, @x, @y

while @@fetch_status = 0
begin
  set @z =
    case when @x2 is null or @x <> @x2
      then 1
      else
        case when @y = @y2
          then @z
          else @z + 1
        end
    end

  update @tbl
  set    z = @z
  where  id = @id

  set @x2 = @x
  set @y2 = @y

  fetch next from cr into @id, @x, @y
end

close cr
deallocate cr

select x, y, z
from   @tbl
order by id
于 2012-08-05T07:32:17.173 回答
1

以为我会把我的解决方案混在一起:

declare @temp table ([row] int identity,[x] char,[y] int)
insert into @temp([x],[y]) values ('a',0)
insert into @temp([x],[y]) values ('a',0)
insert into @temp([x],[y]) values ('a',0)
insert into @temp([x],[y]) values ('a',1)
insert into @temp([x],[y]) values ('a',0)
insert into @temp([x],[y]) values ('a',0)
insert into @temp([x],[y]) values ('a',2)
insert into @temp([x],[y]) values ('a',3)
insert into @temp([x],[y]) values ('b',0)
insert into @temp([x],[y]) values ('b',1)
insert into @temp([x],[y]) values ('b',0)
insert into @temp([x],[y]) values ('b',0)
insert into @temp([x],[y]) values ('b',2)
insert into @temp([x],[y]) values ('b',3)
insert into @temp([x],[y]) values ('b',0)
insert into @temp([x],[y]) values ('b',0)


declare @temp1 table
(
 [row] int
,[x] char
,[y] int
,[change] int
)
insert into @temp1
(
 [row]
,[x]
,[y]
,[change]
)
select 
 [t1].[row]
,[t1].[x]
,[t1].[y] 
,iif([t1].[x] = [t2].[x] and [t1].[y] <> [t2].[y],1,0) [change]
from @temp [t1]
left join @temp [t2] on [t2].[row] = [t1].[row] - 1

select * from @temp1

select 
 [row]
,[x]
,[y]
,(select sum([change]) from @temp1 [t2] where [t2].[row] <= [t1].[row] and [t2].[x] = [t1].[x]) + 1 [z]
from @temp1 [t1]
于 2012-08-05T08:02:22.453 回答
1

这是简单的解决方案:

  declare @temp table ([row] int identity,[x] char,[y] int)
insert into @temp([x],[y]) values ('a',0)
insert into @temp([x],[y]) values ('a',0)
insert into @temp([x],[y]) values ('a',0)
insert into @temp([x],[y]) values ('a',1)
insert into @temp([x],[y]) values ('a',0)
insert into @temp([x],[y]) values ('a',0)
insert into @temp([x],[y]) values ('a',2)
insert into @temp([x],[y]) values ('a',3)
insert into @temp([x],[y]) values ('b',0)
insert into @temp([x],[y]) values ('b',1)
insert into @temp([x],[y]) values ('b',0)
insert into @temp([x],[y]) values ('b',0)
insert into @temp([x],[y]) values ('b',2)
insert into @temp([x],[y]) values ('b',3)
insert into @temp([x],[y]) values ('b',0)
insert into @temp([x],[y]) values ('b',0)

--select * from @temp 

DECLARE @int int=0
;WITH CTE as(
select *,1 as incr from @temp where row=1 
union all
select t.*,
CASE WHEN t.x=c.x then CASE WHEN t.y=c.y then incr else incr+1 end else CASE WHEN t.y=c.y then @int else @int+1 end end as incr
from @temp t inner join CTE c
on t.row=c.row+1
)

select * from CTE
于 2012-08-05T12:35:34.147 回答