2012-07-19 55 views
1

我有一个表:逗号分隔一列的结果以显示在另一列旁边?

lease_id,suite_id

租赁是一个关键,你可以有多个套件的一个租约。我试图创建一个查询,显示我所有的套件是一个租赁的关联,基本上和以下的输出:

lease_id:1 suite_list:A1,A2,B1

不幸的是,我不确定如何处理这个问题(甚至如何开始),因为这对我来说是一种新的问题...任何帮助将不胜感激!

+0

可能的重复 - http://stackoverflow.com/questions/194852/concatenate-many-rows-into-a-single-text-string – vmvadivel 2012-07-19 03:11:41

+0

@vmvadivel除了不,请完整阅读我的问题/看到我发布的答案最终解决方案 – Codingo 2012-07-19 03:19:40

回答

1

您可以使用FOR XML。

该代码将是这样的:

-- Sample data tables 
select * 
into #leases 
from (
    select '1' as lease_id 
    union 
    select '2' as lease_id 
    ) a 

select * 
into #leaseSuites 
from (
    select '1' as lease_id, 
     'A1' as suite_id 
    union 
    select '1' as lease_id, 
     'A2' as suite_id 
    union 
    select '1' as lease_id, 
     'B1' as suite_id 
    union 
    select '2' as lease_id, 
     'C2' as suite_id 
    union 
    select '2' as lease_id, 
     'B3' as suite_id   
    ) a 


-- Creates comma delimited with child table. 
select left(suite_list, LEN(suite_list) - 1) as suite_list 
from (
    SELECT 'lease_id: ' + lease_id + ' ' + 
     'suite_list: ' + (
     SELECT s.suite_id + ',' 
     FROM #leaseSuites s 
     WHERE l.lease_id = s.lease_id 
     ORDER BY s.suite_id 
     FOR XML PATH('') 
    ) AS suite_list 
    FROM #leases l) a 

点击here看到一篇文章用一个例子。

+1

谢谢,我用这个作为我的第二种方法,因为我的原始思路有点慢。不胜感激! – Codingo 2012-07-19 03:21:35

1

我假设你的表叫做LeasedSuites。

我们需要一个功能:

 create function dbo.AllSuite (@l int) returns varchar(100) 
    as begin 
     declare @v varchar(2); 
     declare @r varchar(100); 

     DECLARE sc CURSOR FOR select suite_id from LeasedSuites where lease_id = @l 
     OPEN sc 
     FETCH NEXT FROM sc INTO @v 
     WHILE @@FETCH_STATUS = 0 BEGIN 
     select @r = @r + ',' + @v; 
     FETCH NEXT FROM sc INTO @v 
     END 
     CLOSE sc 
     DEALLOCATE sc 

     return substring(@r, 2, len(@r) - 1); 
    end 

和查询:

 declare @l int; 

    create table #out (lease_id int, suite_str varchar(100) null) 
    insert #out (lease_id) select distinct lease_id from LeasedSuites 

    while (select count(*) from #out where suite_str is null) > 0 begin 
     select @l = min(lease_id) from #out where suite_str is null; 
     update #out set suite_str = dbo.AllSuite(@l) where lease_id = @l; 
    end 

    select 'Lease ID: ' + cast(lease_id as varchar(3)) + ' Suites: ' + suite_str from #out order by l; 

希望这有助于。问候JB

如果这代表一个答案,请标记为答案。

+0

这可行,但不是很流畅或易于维护。 Upvote都一样,但我认为有很多更好的方法来处理这个问题(请参阅其他答案) – Codingo 2012-07-19 03:58:35

1

我已经结束了解决这个问题的两种方式。我的第一个方法,这是不幸的是相当缓慢是:

declare @period_id integer = 
       (
        select period_id 
        from property.period 
        where getdate() between period_start and period_end 
       ) 



;with cte_data as 
(
    select lp.* 
    from property.lease_period lp 
    where period_id = @period_id 
)  
, cte_suites as 
(
    select d.lease_id 
     , (
       select stuff 
       ( 
        ( select ', ' + a.suite_id 
         from 
         ( select a.suite_id 
          from cte_data a 
          where a.lease_id = d.lease_id 
         ) a 
         for xml path('')) 
        , 1, 2, '' 
       ) as suite_list 
      ) suite_list 

    from cte_data d 
    group by d.lease_id 
) , 
cte_count as 
(
    select lease_id , 
      count(suite_id) as 'suites' 
    from property.lease_period 
    where period_id = @period_id 
      and lease_id <> 'No Lease' 
    group by lease_id 

) 
select d.period_id , 
     d.building_id , 
     d.lease_id , 
     s.suite_list 
from cte_data d 
     left outer join cte_suites s 
      on d.lease_id = s.lease_id 
     inner join cte_count c 
      on d.lease_id = c.lease_id 
where period_id = 270 
     and d.lease_id <> 'No Lease' 
     and c.suites > 1 
group by 
     d.period_id , 
     d.building_id , 
     d.lease_id , 
     s.suite_list 

我再剥去了新的发展方向这一回,并重新走近它,从而产生以下(非常非常快):

declare @period_id integer = 
      (
       select period_id 
       from property.period 
       where getdate() between period_start and period_end 
      ) 

;with CteLeaseInMultSuites as 
(
    select period_id, 
      building_id, 
      lease_id 
    from property.lease_period 
    where period_id = @period_id 
      and lease_id <> 'No Lease' 
    group by 
      period_id, 
      building_id, 
      lease_id 
    having count(*) > 1 
) 

select period_id, 
     building_id, 
     lease_id, 
     left(x.suite_list, len(x.suite_list) - 1) as suite_list 
from CteLeaseInMultSuites lm 
     cross apply 
     (
      select suite_id + ', ' 
      from CteLeaseInMultSuites lmx 
        inner join property.lease_period lp 
         on lp.period_id = lmx.period_id 
         and lp.building_id = lmx.building_id 
         and lp.lease_id = lmx.lease_id 
      where lmx.period_id = lm.period_id 
        and lmx.building_id = lm.building_id 
        and lmx.lease_id = lm.lease_id 
      for xml path('') 
     ) x (suite_list)