Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/79.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何在一对多选择中将同一字段的多行值合并为一个字符串?_Sql_Sybase - Fatal编程技术网

Sql 如何在一对多选择中将同一字段的多行值合并为一个字符串?

Sql 如何在一对多选择中将同一字段的多行值合并为一个字符串?,sql,sybase,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 t

设想以下两个表:

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
中的所有行,同时将
OtherTable
中与每个
MainId
匹配的所有行组合到结果集中的单个字段中

想象一下数据:

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'
最优雅的方式是什么


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

在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()
函数处理额外的逗号,执行条件聚合以获取每个值。上述方法适用于前三个值。如果您想要更多,那么您需要添加更多子句。

好的,下面是我在Sybase 13.x中实现它的方法。此代码的优点是不限于许多
Name
s

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

但它的缺点是使用光标和工作表,这会使整个过程变慢,至少在有大量数据的情况下是如此。

与您的答案一样有趣;我无法让(
row_number())over(partition by…
工作,因为Sybase一直抱怨“over”附近有语法错误。@svip。并非所有版本的Sybase都支持窗口功能。我猜您使用的是旧版本。
status
有多少不同的值?在我的实际表中(比示例中的表更详细),
status
有3个值:0、1和2。如果为2,则在else end子句中使用
大小写呈现“1”,否则为“0”。那东西有用。在我的实现中,我按
Name
排序。好吧,如果它在12.x中不起作用,恐怕我必须传递功能。因为我们的很多客户仍然运行12.x。我正在考虑使用一个帮助表和一个游标。在“其他”表中是否有一个有限的名称列表?你也可以这样做,一个名字一个名字。