在这种情况下,我有两个已加入的表,并且由于每个医生都能够拥有多个许可证,因此会创建多个副本。我想转向并创建多个许可证状态并将其他列编号到表1,如下所示。
这需要动态完成,因为它可能是分配给一位医生的大量许可证。
表1看起来像这样。
$pdf = new Fpdi('P', 'mm', 'A4');
...
$pdf->SetX(14);
$pdf->write(40, iconv('UTF-8', 'windows-1252//TRANSLIT//IGNORE', $invoiceDetails->getCompanyName()));
...
// return output for preview
return $pdf->Output('I');
表2
assignid physician_name profession
-------------------------------
1 bob md
2 travis do
3 ryan md
4 pete pa
5 susan np
6 ashley cnp
加入
assignid license_state license_num
-------------------------------
1 oh 561
2 mi 987
3 ca 785
4 ny 965
4 mi 125
5 oh 369
5 ca 541
我想动态地将连接表更改为这样。
assignid physician_name profession license_state license_num
----------------------------------------------------------------
1 bob md oh 561
2 travis do mi 987
3 ryan md ca 785
4 pete pa ny 965
4 pete pa mi 125
5 susan np oh 369
5 susan np ca 541
我尝试了这条路线,但这会将状态作为列标题。
assignid physician_name profession license_state1 license_num1 license_state2 license_num2
--------------------------------------------------------------------------------------------------
1 bob md oh 561
2 travis do mi 987
3 ryan md ca 785
4 pete pa ny 965 mi 125
5 susan np oh 369 ca 541
结果
WITH pivotdata AS (
SELECT assignid,physician_name, profession, license_state,license_num
FROM dbo.Physicians p JOIN dbo.Licenses l ON p.AssignID = l.AssignID
)
SELECT *
FROM
pivotdata
PIVOT (MAX(license_num) FOR license_state IN ([oh], [mi], [ca],[ny])) TT;
答案 0 :(得分:0)
您可以使用动态交叉表来解决此问题。我从Jeff Moden和他的文章中学到了这种技巧。 http://www.sqlservercentral.com/articles/Crosstab/65048/
if OBJECT_ID('tempdb..#Physicians') is not null
drop table #Physicians
create table #Physicians
(
AssignID int
, PhysicianName varchar(20)
, Profession varchar(10)
)
insert #Physicians values
(1, 'bob', 'md')
, (2, 'travis', 'do')
, (3, 'ryan', 'md')
, (4, 'pete', 'pa')
, (5, 'susan', 'np')
, (6, 'ashley', 'cnp')
if OBJECT_ID('tempdb..#Licenses') is not null
drop table #Licenses
create table #Licenses
(
AssignID int
, LicenseState char(2)
, LicenseNum int
)
insert #Licenses values
(1, 'oh', 561)
, (2, 'mi', 987)
, (3, 'ca', 785)
, (4, 'ny', 965)
, (4, 'mi', 125)
, (5, 'oh', 369)
, (5, 'ca', 541)
declare @StaticPortion nvarchar(2000) =
'with OrderedResults as
(
SELECT p.AssignID
, p.PhysicianName
, p.Profession
, l.LicenseState
, l.LicenseNum
, ROW_NUMBER() over(partition by p.AssignID order by l.LicenseState) as RowNum
FROM #Physicians p
JOIN #Licenses l ON p.AssignID = l.AssignID
)
select AssignID';
declare @DynamicPortion nvarchar(max) = '';
declare @FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by AssignID order by AssignID';
--the following cte is a tally table (another trick I learned from Jeff Moden)
with E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E2
)
select @DynamicPortion = @DynamicPortion +
', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then LicenseState end) as LicenseState' + CAST(N as varchar(6)) + CHAR(10)
+ ', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then LicenseNum end) as LicenseNum' + CAST(N as varchar(6)) + CHAR(10)
from cteTally t
where t.N <=
(
select top 1 Count(p.AssignID)
FROM #Physicians p
JOIN #Licenses l ON p.AssignID = l.AssignID
group by p.AssignID
order by COUNT(*) desc
)
declare @SqlToExecute nvarchar(max) = @StaticPortion + @DynamicPortion + @FinalStaticPortion;
--you can comment the following. it is here for now so you can view the dynamic sql before it executes
select @SqlToExecute
--Once you are satisfied that the dynamic sql generated is correct simply uncomment the below line
--exec sp_executesql @SqlToExecute