SQL Server:将结果从一对多查询展平

kin*_*nix 5 sql sql-server one-to-many flatten sql-server-2008

好的,我有一个输入订单的系统,每个订单都可以附加任意数量的债券,工作和项目编号.该OrderDetails表包含一个orderID用于转到OrderNumbers表并获取所有附加"数字"到此订单,然后根据在numType那里找到的列,它进入三个表之一(bond,job,project)并检索实际数字为用户显示和打印.

这意味着,如果该订单附加了3个项目编号,则尝试查询订单以搜索某个项目编号可以为同一订单返回3行.

我希望能够返回我的查询结果,只有1行的订单,以及包含所有3个分隔形式的项目的列,这可能吗?

这是我当前的查询,当订单附加多个相同类型的数字时,每个订单返回多行...

SELECT 
    ISNULL(b.Descr,'') as Bond, ISNULL(PO.Description,'') as PO, 
    ISNULL(j.Descr,'') as Job, ISNULL(Proj.Descr,'') as Project, 
    d.OrdNbr, d.BillofLadingNbr, d.TripAndDeliveryTicketNbr
FROM 
    OrderDetail d 
LEFT JOIN 
    OrderItemNumbers n ON d.OWID = n.LoadOWID 
LEFT JOIN 
    Bond b ON n.NumberOWID = b.OWID AND n.NumType = 0
LEFT JOIN 
    PONumbers PO ON n.NumberOWID = PO.OWID AND n.NumType = 1 
LEFT JOIN 
    Job j ON n.NumberOWID = j.OWID AND n.NumType = 2 
LEFT JOIN 
    Project Proj ON n.NumberOWID = Proj.OWID AND n.NumType = 3 
WHERE 
    d.OWID = 'BTBD1004'
Run Code Online (Sandbox Code Playgroud)

这是我得到的结果....

Bond    PO              Job Project         OrdNbr      BillofLadingNbr
                            82001-8177-44   BTBD000063  BTBD000072  
        4.158 Kingsport                     BTBD000063  BTBD000072  
                            IME-81-1(118)   BTBD000063  BTBD000072  
Run Code Online (Sandbox Code Playgroud)

这就是我想要得到的......(基本上扁平化前4列)

Bond    PO              Job Project                         OrdNbr      BillofLadingNbr
        4.158 Kingsport     82001-8177-44, IME-81-1(118)    BTBD000063  BTBD000072  
Run Code Online (Sandbox Code Playgroud)

任何帮助表示赞赏!谢谢,道格

rse*_*nna 6

根据您的示例,似乎没有匹配的记录BondJob表.如果有,你会得到这样的东西:

BOND        PO              JOB      PROJECT        ORDNBR     BILLOFLADINGNBR  
Some bond                                           BTBD000063 BTBD000072
            4.158 Kingsport                         BTBD000063 BTBD000072
                            Some job                BTBD000063 BTBD000072
                                     82001-8177-44  BTBD000063 BTBD000072
                                     IME-81-1(118)  BTBD000063 BTBD000072
Run Code Online (Sandbox Code Playgroud)

该结果集似乎很"疏",因为你加入OrderItemNumbers直接到你的主查询:此表中有一个明显的一行代表一个子表(PONumbers,Job,Project),所以你会得到一个截然不同的,分开列各加盟.为了避免这种情况,您可以OrderItemNumbers每个子表连接,然后将此子查询与OrderDetail(通过共享LoadOWID)连接:

SELECT
    ISNULL(b.Descr, '') as Bond,
    ISNULL(PO.Description, '') as PO, 
    ISNULL(j.Descr, '') as Job,
    ISNULL(Proj.Descr, '') as Project, 
    d.OrdNbr,
    d.BillofLadingNbr,
    d.TripAndDeliveryTicketNbr
FROM 
    OrderDetail d 
    LEFT JOIN (
        SELECT aux.*, n.*
        FROM Bond aux INNER JOIN OrderItemNumbers n ON n.NumberOWID = aux.OWID AND n.NumType = 0
    ) AS b
        ON b.LoadOWID = d.OWID
    LEFT JOIN (
        SELECT aux.*, n.*
        FROM PONumbers aux INNER JOIN OrderItemNumbers n ON n.NumberOWID = aux.OWID AND n.NumType = 1
    ) AS PO
        ON PO.LoadOWID = d.OWID
    LEFT JOIN (
        SELECT aux.*, n.*
        FROM Job aux INNER JOIN OrderItemNumbers n ON n.NumberOWID = aux.OWID AND n.NumType = 2
    ) AS j
        ON j.LoadOWID = d.OWID
    LEFT JOIN (
        SELECT aux.*, n.*
        FROM Project aux INNER JOIN OrderItemNumbers n ON n.NumberOWID = aux.OWID AND n.NumType = 3
    ) AS Proj
        ON Proj.LoadOWID = d.OWID
WHERE 
    d.OWID = 'BTBD1004'
Run Code Online (Sandbox Code Playgroud)

这样你将得到以下结果:

Bond       PO               Job       Project         OrdNbr      BillofLadingNbr
Some bond  4.158 Kingsport  Some job  82001-8177-44   BTBD000063  BTBD000072  
Some bond  4.158 Kingsport  Some job  IME-81-1(118)   BTBD000063  BTBD000072
Run Code Online (Sandbox Code Playgroud)

我同意这不完全是你所要求的.你似乎也需要在Project桌子上进行某种"部分旋转" (至少).

从理论上讲,这也是可能的,但我不会这样做.这显然是一个表示要求,在SQL层上实现它的成本太高了.

编辑

为了获得完整的平坦结果集,您可以这样做(基于此SO答案):

DECLARE @bonds   VARCHAR(MAX)
DECLARE @numbers VARCHAR(MAX)
DECLARE @jobs    VARCHAR(MAX)
DECLARE @projs   VARCHAR(MAX)

DECLARE @owid VARCHAR(10) = 'BTBD1004'

SELECT
    @bonds = COALESCE(@bonds + ', ', '') + aux.Descr
FROM
    Bond aux
    INNER JOIN OrderItemNumbers n
        ON n.NumberOWID = aux.OWID AND n.NumType = 0
WHERE
    n.LoadOWID = @owid

SELECT
    @numbers = COALESCE(@numbers + ', ', '') + aux.Description
FROM
    PONumbers aux
    INNER JOIN OrderItemNumbers n
        ON n.NumberOWID = aux.OWID AND n.NumType = 1
WHERE
    n.LoadOWID = @owid

SELECT
    @jobs = COALESCE(@jobs + ', ', '') + aux.Descr
FROM
    Job aux
    INNER JOIN OrderItemNumbers n
        ON n.NumberOWID = aux.OWID AND n.NumType = 2
WHERE
    n.LoadOWID = @owid

SELECT
    @projs = COALESCE(@projs + ', ', '') + aux.Descr
FROM
    Project aux
    INNER JOIN OrderItemNumbers n
        ON n.NumberOWID = aux.OWID AND n.NumType = 3
WHERE
    n.LoadOWID = @owid

SELECT
    @bonds,
    @numbers, 
    @jobs,
    @projs,
    d.OrdNbr,
    d.BillofLadingNbr,
    d.TripAndDeliveryTicketNbr
FROM 
    OrderDetail d 
WHERE 
    d.OWID = @owid
Run Code Online (Sandbox Code Playgroud)

这将导致:

Bond       PO               Job       Project                        OrdNbr      BillofLadingNbr
Some bond  4.158 Kingsport  Some job  82001-8177-44, IME-81-1(118)   BTBD000063  BTBD000072  
Run Code Online (Sandbox Code Playgroud)

如果您获得许多债券x许多PO的x多个工作OWID也是如此.

恕我直言,很好地说明了我试图说的话:是的,它做了你需要的东西,但它是丑陋的地狱.当然,如果你不在乎,继续(只需添加一些触发器,你会觉得它再次是1995年:P).

希望能帮助到你.