如何检索多个详细记录加上主记录作为单行?

时间:2013-02-09 08:47:30

标签: sql-server pivot crosstab

我有两个表格,其结构与此类似:

人:

ID   Name   Age
 1   Jack    25
 2   Jill    23

试验:

ID  PersonID  TestID  Result
 1         1       1     125
 2         1       2     120
 3         1       3      75
 4         2       1      90
 5         2       2      95
 6         2       3     7.2

有没有办法使用单个语句检索数据,方法是主表中的每个记录都显示在一行中?像这样:

PersonID  Name  Age  Test1  Test2  Test3
       1  Jack   25    125    120     75
       2  Jill   23     90     95    7.2

到目前为止,我提出的唯一方法是创建一个迭代详细记录并填充临时表的函数。不是很优雅。

提前致谢

2 个答案:

答案 0 :(得分:2)

要获得此结果,您需要使用PIVOT功能。这会将多行数据转换为列。

如果您提前知道这些值,或者您的TestId值的数量有限,那么您可以对查询进行硬编码,使查询保持静态。

SELECT Name,
  Age,
  [1] AS Test1,
  [2] AS Test2,
  [3] AS Test3 
FROM
( 
  SELECT P.Name, P.Age, t.TestID, t.Result 
  FROM tests t
  INNER JOIN person P 
  ON p.ID = t.PersonID
) T 
PIVOT
(
  sum(Result) 
  FOR TestID IN ([1], [2], [3])
) piv;

请参阅SQL Fiddle with Demo

但是如果您有TestId个未知数量的值,那么您将需要使用动态SQL在运行时生成列列表。您的代码将是:

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

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(testId) 
                    from tests
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

select @colNames = STUFF((SELECT distinct ',' + QUOTENAME(testId) +' as Test'+cast(testId as varchar(10))
                    from tests
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT Name, age, ' + @colnames + ' from 
             (
                select P.Name, P.Age, t.TestID, t.Result 
                from tests t
                inner join person P 
                  on p.ID = t.PersonID
            ) x
            pivot 
            (
                sum(Result)
                for TestID in (' + @cols + ')
            ) p '

execute(@query)

请参阅SQL Fiddle with Demo

它们都将产生相同的结果,不同之处在于,如果测试ID的数量发生变化,动态的将增加/减少列:

| NAME | AGE | TEST1 | TEST2 | TEST3 |
--------------------------------------
| Jack |  25 |   125 |   120 |    75 |
| Jill |  23 |    90 |    95 |   7.2 |

答案 1 :(得分:1)

您可以在TestID上进行转轴

你去......它有点乱,但你可以改进它:)

SELECT Name,Age,SUM([1]) AS Test1,SUM([2]) AS Test2,SUM([3]) AS Test3
FROM(
SELECT P.Name,P.Age,Te.ID, TestID,Result
FROM Test Te
INNER JOIN dbo.Person P ON P.ID=Te.PersonID) T
PIVOT(MAX(T.Result) FOR TestID IN([1],[2],[3])) AS pvt
GROUP BY Name,Age

继承人一些链接

http://msdn.microsoft.com/en-us/library/ms177410(v=sql.105).aspx http://www.codeproject.com/Questions/393632/How-to-use-Pivot-in-SQL http://blog.sqlauthority.com/2008/06/07/sql-server-pivot-and-unpivot-table-examples/