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。我正在考虑使用一个帮助表和一个游标。在“其他”表中是否有一个有限的名称列表?你也可以这样做,一个名字一个名字。