私はテーブルを持っています:
lease_id、suite_id
リースが鍵であり、複数のスイートを 1 つのリースにすることができます。リースが関連付けられているすべてのスイートを表示するクエリを作成しようとしています。基本的には次のような出力です。
lease_id: 1 suite_list: A1、A2、B1
残念ながら、これは私にとって新しい種類の問題であるため、これにアプローチする方法(または開始方法さえも)がわかりません...どんな助けも大歓迎です!
私はテーブルを持っています:
lease_id、suite_id
リースが鍵であり、複数のスイートを 1 つのリースにすることができます。リースが関連付けられているすべてのスイートを表示するクエリを作成しようとしています。基本的には次のような出力です。
lease_id: 1 suite_list: A1、A2、B1
残念ながら、これは私にとって新しい種類の問題であるため、これにアプローチする方法(または開始方法さえも)がわかりません...どんな助けも大歓迎です!
あなたのテーブルは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
これが回答を表す場合は、回答としてマークしてください。
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
ここをクリックして、例を含む記事を参照してください。
私はこれを2つの方法で解決することになりました。残念ながら非常に遅い私の最初の方法は次のとおりです。
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)