组合多个表中多行的数据并以单行显示

时间:2014-10-27 07:46:00

标签: sql-server

我正在编写查询以从多个表中获取结果它给出了所有列中具有重复值的多行期望我希望那些列是短的并且在单行中显示,这些是我的表

表名:AppUesrs

Id  Name    Gender
1   Goga    M
2   Maja    M
3   Phadu   M
4   Kaku    F
5   Seefa   F

表名:AppProducts

Id  Name    Value
1   Bc090   10
2   Bc080   15
3   Mc070   2
4   Mc100   16
5   Bc110   15

表名:AppOrders

Id  Date        ExpDate
1   08/9/2014   10/10/2015
2   18/9/2014   08/11/2015
3   20/9/2014   25/12/2015
4   01/10/2014  14/12/2015
5   19/10/2014  15/2/2016

和 表名:ProductOwners

OId  PId UId
1   1   2
1   2   2
1   5   2
2   3   5
3   4   4
3   3   4
3   5   4
3   1   4

我正在为它编写查询,并显示这样的数据

select O.Id, P.ProductName, U.Name ,O.Date,O.ExpDate 
from AppProductOwners PO, AppProducts P, AppOrders O, AppUsers U 
Where PO.AppOrderId = O.Id AND PO.ProductsId = P.Id AND PO.AppUserId = U.Id

它提供了像

这样的数据
O.Id    P.Name  U.Name  O.Date  O.ExpDate
   1    Bc090   Maja    08/9/2014   10/10/2015
   1    Bc080   Maja    08/9/2014   10/10/2015
   1    Bc110   maja    08/9/2014   10/10/2015

我想要像

这样的数据
  O.Id  P.Name             U.Name   O.Date  O.ExpDate
   1    Bc090,Bc080,Bc110   Maja    08/9/2014   10/10/2015

如果有人帮我写这个问题

如果我像

那样写
SELECT  O.ID,
    PName = STUFF(( SELECT  ',' + P.ProductName
                    FROM   AppProductOwners PO
                            INNER JOIN AppProducts P
                                ON P.Id = PO.ProductsId
                    AND   U.Id = PO.AppUserId
                    FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)'), 1, 1, ''),
    U.FirstName, U.LastName,
    O.Date,
    o.ExpDate
FROM    AppUsers U
    INNER JOIN AppOrders O
        ON u.id = O.ID;

它没有显示任何内容,如果我像

那样写
SELECT  O.ID,
    PName = STUFF(( SELECT  ',' + P.ProductName
                    FROM   AppProductOwners PO
                            INNER JOIN AppProducts P
                                ON P.Id = PO.ProductsId
                    AND   AppUsers.Id = PO.AppUserId
                    FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)'), 1, 1, ''),
    U.FirstName, U.LastName,
    O.Date,
    o.ExpDate
FROM    AppUsers U
    INNER JOIN AppOrders O
        ON u.id = O.ID;

它给出了错误

Msg 4104, Level 16, State 1, Line 6
The multi-part identifier "AppUsers.Id" could not be bound.

1 个答案:

答案 0 :(得分:0)

您可以使用SQL Server XML扩展将行连接到一个列中:

SELECT  O.ID,
        PName = STUFF(( SELECT  ',' + P.Name
                        FROM    PO
                                INNER JOIN P
                                    ON P.ID = PO.PID
                        WHERE   U.ID = PO.UID
                        FOR XML PATH(''), TYPE
                    ).value('.', 'NVARCHAR(MAX)'), 1, 1, ''),
        U.Name,
        O.Date,
        o.ExpDate
FROM    U
        INNER JOIN O
            ON u.id = O.ID;

有关其工作原理的详细说明,请参阅this answer

如果您只想包含PName不为空的行,那么稍微调整查询以使用CROSS APPLY可能更容易:

SELECT  O.ID,
        PName = STUFF(p.PName.value('.', 'NVARCHAR(MAX)'), 1, 1, ''),
        U.Name,
        O.Date,
        o.ExpDate
FROM    U
        INNER JOIN O
            ON u.id = O.ID
        CROSS APPLY
        (   SELECT  ',' + P.Name
            FROM    PO
                    INNER JOIN P
                        ON P.ID = PO.PID
            WHERE   U.ID = PO.UID
            FOR XML PATH(''), TYPE
        ) p (PName)
WHERE   p.Pname IS NOT NULL;

<强> Examples on SQL Fiddle


修改

我认为我最初误解了您的架构,以及OrdersUsers的关联方式,我认为这会按要求运作:

SELECT  O.ID,
        PName = STUFF(p.PName.value('.', 'NVARCHAR(MAX)'), 1, 1, ''),
        U.Name,
        O.Date,
        o.ExpDate
FROM    AppUsers AS U
        CROSS JOIN AppOrders AS O
        CROSS APPLY
        (   SELECT  ',' + P.Name
            FROM    AppProductOwners AS PO
                    INNER JOIN AppProducts AS P
                        ON P.ID = PO.PID
            WHERE   U.ID = PO.UID
            AND     O.ID = PO.OID
            FOR XML PATH(''), TYPE
        ) p (PName)
WHERE   p.Pname IS NOT NULL;