将表行连接为列值sql

时间:2017-11-08 15:42:56

标签: sql sql-server join pivot pivot-table

在这种情况下,我有两个已加入的表,并且由于每个医生都能够拥有多个许可证,因此会创建多个副本。我想转向并创建多个许可证状态并将其他列编号到表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;

1 个答案:

答案 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