1

我有一个数据库表,如下所示:

EVENT_ID TEXT_FRO TEXT_TO
55001              05
55001    05        10
55001    10        15
55001    15        20
55001    20        30
56215    06        11
56215    11        22

我需要编写一个查询(或 SP)来生成一个结果集,以列出每个不同 event_ID 的所有动作,如下所示:

Event ID Movements
55001    05 10 15 20 30
56215    06 11 22

我怎样才能做到这一点?

*编辑以简化示例

4

2 回答 2

1

如果您使用函数和光标,这非常简单:

use tempdb
go

create table tmp (
  EVENT_ID int, 
  TEXT_FRO varchar(10), 
  TEXT_TO varchar(10)
)
go

insert into tmp values
(55001, NULL, '05'),
(55001, '05', '26'),
(55001, '26', '28'),
(55001, '28', '27'),
(55001, '27', '26'),
(55001, '26', '27'),
(55001, '27', '28'),
(55001, '28', '30'),
(55001, '30', '40'),
(56215, '06', '11'),
(56215, '11', '22')
go

您必须创建一个函数来组装连接的字符串:

create function fnConcat (@id int) returns varchar(255) as
begin
  declare @rtn varchar(255) = '', @fro varchar(10), @to varchar(10), @cnt int = 1

  declare cr cursor local for
    select TEXT_FRO, TEXT_TO
    from   tmp
    where  EVENT_ID = @id

  open cr
  fetch next from cr into @fro, @to

  while @@fetch_status = 0
  begin
    if @cnt = 1 and @fro is not null
      set @rtn = @rtn + @fro + ' '

    set @rtn = @rtn + @to + ' '

    set @cnt = @cnt + 1
    fetch next from cr into @fro, @to
  end

  close cr
  deallocate cr

  set @rtn = left(@rtn, datalength(@rtn) - 1)

  return @rtn
end
go

如果每个唯一的 EVENT_ID 只调用一次函数会更有效因此我们distinct在子查询中选择 EVENT_ID:

select x.EVENT_ID as [Event ID], dbo.fnConcat(x.EVENT_ID) as Movements
from (
  select distinct EVENT_ID
  from tmp
) as x
go

然后清理:

drop table tmp
go
drop function fnConcat
go

结果如下:

Event ID    Movements
----------- ---------------------------
55001       05 26 28 27 26 27 28 30 40
56215       06 11 22
于 2012-10-02T03:37:07.493 回答
1

您可以使用递归公用表表达式来执行此操作。

出于测试目的,我在测试表中添加了一个列来标识事件的顺序,以便能够识别第一个:

create table movements 
(
  event_id   INTEGER,
  text_fro   VARCHAR(10),
  text_to    VARCHAR(10),
  sort_ord   INTEGER
);

insert into movements (event_id, text_fro, text_to, sort_ord)
values
(55001,null,'05',1),
(55001,'05','10',2),
(55001,'10','15',3),
(55001,'15','20',4),
(55001,'20','30',5),
(56215,'06','11',1),
(56215,'11','22',2)
;

with mvt as (
   select m1.event_id as root_id,
          m1.event_id,
          cast(coalesce(m1.text_fro,'') + ' ' + m1.text_to as varchar(8000)) as path,
          m1.text_fro,
          m1.text_to,
          m1.sort_ord
   from movements m1
   where m1.text_fro is null
   or m1.sort_ord = (select min(sort_ord) from movements m2 where m1.event_id = m2.event_id)

   union all 

   select p.root_id,
          c.event_id,
          p.path + ' ' + c.text_to,
          c.text_fro,
          c.text_to,
          c.sort_ord
   from movements c
     join mvt p on p.text_to = c.text_fro
)
select root_id, max(ltrim(path)) as movements
from mvt
group by root_id;

这是一个SQLFiddle 演示

不过,我不确定如何处理事件循环中的循环。

于 2012-10-02T06:37:31.807 回答