如何在一对多选择中将多行中相同字段的值组合成一个字符串?

时间:2013-08-19 14:40:26

标签: sql sybase

想象一下以下两个表:

create table MainTable (
  MainId integer not null, -- This is the index
  Data varchar(100) not null
)

create table OtherTable (
  MainId integer not null,    -- MainId, Name combined are the index.
  Name varchar(100) not null,
  Status tinyint not null
)

现在,我想从MainTable中选择所有行,同时将MainId中与每个OtherTable匹配的所有行合并到结果集中的单个字段中。

想象一下数据:

MainTable:
1, 'Hi'
2, 'What'

OtherTable:
1, 'Fish', 1
1, 'Horse', 0
2, 'Fish', 0

我想要一个像这样的结果集:

MainId, Data,   Others
1,      'Hi',   'Fish=1,Horse=0'
2,      'What', 'Fish=0'

最优雅的方法是什么?

(不要担心逗号位于结果字符串的前面或末尾。)

2 个答案:

答案 0 :(得分:1)

在Sybase中没有非常优雅的方法。不过,这是一种方法:

select 
  mt.MainId, 
  mt.Data,
  Others = stuff((
             max(case when seqnum = 1 then ','+Name+'='+cast(status as varchar(255)) else '' end) +
             max(case when seqnum = 2 then ','+Name+'='+cast(status as varchar(255)) else '' end) +
             max(case when seqnum = 3 then ','+Name+'='+cast(status as varchar(255)) else '' end)
           ), 1, 1, '')
from MainTable mt 
  left outer join
    (select 
       ot.*, 
       row_number() over (partition by MainId order by status desc) as seqnum
     from OtherTable ot
    ) ot
    on mt.MainId = ot.MainId
group by
  mt.MainId, md.Data

也就是说,它枚举了第二个表中的值。然后使用stuff()函数来处理额外的逗号,然后进行条件聚合以获取每个值。以上工作原理为前三个值。如果你想要更多,那么你需要添加更多的子句。

答案 1 :(得分:0)

好吧,这是我在Sybase 13.x中实现它的方式。此代码的优点是不限于Name个。

create proc
as
  declare
    @MainId int,
    @Name   varchar(100),
    @Status tinyint

  create table #OtherTable (
    MainId     int          not null,
    CombStatus varchar(250) not null
  )

  declare OtherCursor cursor for
    select
        MainId, Name, Status
      from
        Others

  open OtherCursor
    fetch OtherCursor into @MainId, @Name, @Status
    while (@@sqlstatus = 0) begin -- run until there are no more
      if exists (select 1 from #OtherTable where MainId = @MainId) begin
        update #OtherTable
          set CombStatus = CombStatus + ','+@Name+'='+convert(varchar, Status)
          where
            MainId = @MainId
      end else begin
        insert into #OtherTable (MainId, CombStatus)
          select
            MainId = @MainId,
            CombStatus = @Name+'='+convert(varchar, Status)
      end

      fetch OtherCursor into @MainId, @Name, @Status
    end
  close OtherCursor

  select
      mt.MainId,
      mt.Data,
      ot.CombStatus
    from
      MainTable mt
        left join #OtherTable ot
          on mt.MainId = ot.MainId

但它确实有使用游标和工作表的缺点,这可能 - 至少有大量数据 - 使整个过程变慢。