动态PIVOT,从两个表的JOIN返回结果

M.A*_*Ali 2 sql sql-server pivot sql-server-2008

我认为是一个相当简单的查询似乎比我预期的更棘手.

我有两张桌子.与一对多的关系.我想要做的是表2返回的任何记录,我希望它在一个单独的列中.我已经设法在以下查询中使用相对较小的数据并知道第二个表返回的内容.

样本数据

DECLARE @TABLE1 TABLE(UserID INT,Episode INT ,[Value] VARCHAR(100))
INSERT INTO @TABLE1 VALUES
(1, 1,'VALUE 1-1'),(1, 2,'VALUE 1-2')

DECLARE @TABLE2 TABLE(UserID INT,Episode INT ,[Details] VARCHAR(100))
INSERT INTO @TABLE2 VALUES
(1, 1,'Details 1'),(1, 1,'Details 2'),(1, 2,'Details 1'),(1, 2,'Details 2') 
Run Code Online (Sandbox Code Playgroud)

简单加入

SELECT  ONE.UserID
      , ONE.Episode
      , ONE.Value
      , TWO.Details 
FROM @TABLE1 ONE INNER JOIN @TABLE2 Two
ON ONE.UserID = TWO.UserID 
AND ONE.Episode = TWO.Episode

????????????????????????????????????????????
? UserID ? Episode ?   Value   ?  Details  ?
????????????????????????????????????????????
?      1 ?       1 ? VALUE 1-1 ? Details 1 ?
?      1 ?       1 ? VALUE 1-1 ? Details 2 ?
?      1 ?       2 ? VALUE 1-2 ? Details 1 ?
?      1 ?       2 ? VALUE 1-2 ? Details 2 ?
????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我想要PIVOT详细信息列.我设法用一个非常简单的PIVOT查询,如下所示

PIVOT查询

SELECT * FROM
(
SELECT  ONE.UserID
      , ONE.Episode
      , ONE.Value
      , TWO.Details 
FROM @TABLE1 ONE INNER JOIN @TABLE2 Two
ON ONE.UserID = TWO.UserID AND ONE.Episode = TWO.Episode)Q
PIVOT (MAX(Details)
       FOR Details
       IN ([Details 1], [Details 2]))p

????????????????????????????????????????????????????????
? UserID ? Episode ?   Value   ? Details 1 ? Details 2 ?
????????????????????????????????????????????????????????
?      1 ?       1 ? VALUE 1-1 ? Details 1 ? Details 2 ?
?      1 ?       2 ? VALUE 1-2 ? Details 1 ? Details 2 ?
????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

这正是我想要的,所有记录从表中的两个在命名为列返回Details 1,Details 2Details 3等...

在这种情况下,它起作用,因为重新调整的数据是字符串,如"详细信息1","详细信息2"和"详细信息3".

但是当我不知道将从table2返回多少行时,我将努力解决这些问题.

另外一个重要的事情是,从表2返回的数据Large Text values由连接的几列组成.

我试图按照给定的逻辑this,thisthis问题,但没有喜悦.

任何帮助任何指针在正确的方向非常感谢,提前谢谢你.

Tar*_*ryn 6

也许我错过了一些东西,但你应该能够PIVOT数据,但你需要实现row_number()以帮助生成列.

关键是使用类似于的查询:

SELECT  ONE.UserID,
  ONE.Episode,
  ONE.Value,
  TWO.Details,
  'Details'
    +cast(row_number() over(partition by one.userid, one.episode
                           order by two.details) as varchar(10)) seq
FROM TABLE1 ONE 
INNER JOIN TABLE2 Two
  ON ONE.UserID = TWO.UserID 
AND ONE.Episode = TWO.Episode
Run Code Online (Sandbox Code Playgroud)

这将为新列名创建一个唯一的序列,然后您可以应用PIVOT:

select userid, episode,
  value,
  details1,
  details2
from
(
  SELECT  ONE.UserID,
    ONE.Episode,
    ONE.Value,
    TWO.Details,
    'Details'
      +cast(row_number() over(partition by one.userid, one.episode
                              order by two.details) as varchar(10)) seq
  FROM TABLE1 ONE 
  INNER JOIN TABLE2 Two
    ON ONE.UserID = TWO.UserID 
  AND ONE.Episode = TWO.Episode
) d
pivot
(
  max(details)
  for seq in (Details1, Details2)
) piv;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo.然后你可以将它转换为动态SQL:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME('Details'+cast(seq as varchar(10))) 
                    from 
                    (
                      select 
                        row_number() over(partition by one.userid, one.episode
                                                order by two.details) seq
                        FROM TABLE1 ONE 
                        INNER JOIN TABLE2 Two
                          ON ONE.UserID = TWO.UserID 
                        AND ONE.Episode = TWO.Episode
                    ) d
                    group by seq
                    order by seq
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT userid, episode, value, ' + @cols + ' 
            from 
            (
             SELECT  ONE.UserID,
                ONE.Episode,
                ONE.Value,
                TWO.Details,
                ''Details''
                  +cast(row_number() over(partition by one.userid, one.episode
                                          order by two.details) as varchar(10)) seq
              FROM TABLE1 ONE 
              INNER JOIN TABLE2 Two
                ON ONE.UserID = TWO.UserID 
              AND ONE.Episode = TWO.Episode
            ) x
            pivot 
            (
                max(details)
                for seq in (' + @cols + ')
            ) p '

execute sp_executesql @query;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo.给你结果:

| USERID | EPISODE |     VALUE |  DETAILS1 |  DETAILS2 |
|--------|---------|-----------|-----------|-----------|
|      1 |       1 | VALUE 1-1 | Details 1 | Details 2 |
|      1 |       2 | VALUE 1-2 | Details 1 | Details 2 |
Run Code Online (Sandbox Code Playgroud)