【问题标题】:How to retrieve multiple detail records plus the master record as a single row?如何检索多个详细记录和主记录作为单行?
【发布时间】:2013-02-09 08:47:30
【问题描述】:

我有两个结构类似于这样的表:

人:

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

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

提前致谢

【问题讨论】:

标签: sql-server pivot crosstab


【解决方案1】:

为了得到这个结果,你需要使用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 |

【讨论】:

    【解决方案2】:

    您可以在 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/

    【讨论】:

    • 我迷路了。请您为我在这里提供的数据写一份声明吗?
    • 谢谢。如果事先不知道明细记录的数量,是否可以使用类似的语句?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-05
    • 2021-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多