PostgreSQL - 如何呈现更多与XML的一对多关系

时间:2014-07-23 18:49:08

标签: sql xml postgresql aggregate-functions outer-join

我想从我的数据库的三个表创建XML导出。

表:客户,订单,付款。当然,一个客户可能有更多的订单和更多的付款。

我已经在stackoverflow上看到了这个很棒的主题:“How to render one to many relationships to XML with PostgreSQL",它帮助我找到了如何构建查询。但是,只有当我加入表客户时,这些指令才适用于我订单或付款,而不是他们两个。我没有找到如何构建查询,所以我在模型中输出如下:

<Customer>
<Name/>
<Orders>
    <Order>
        <id/>
        <date/>
        <content/>
    </Order>
</Orders>
<Payments>
    <Payment>
        <id/>
        <date/>
        <amount/>
    </Payment>
</Payments>
</Customer>

尝试这样做:

SELECT xmlelement(name "Customer",
                    xmlelement(name "Name", c.name),
       xmlelement(name "Orders",
             xmlagg(xmlelement(name "Order",
                        xmlelement(name "id", o.id),                    
                        xmlelement(name "date", o.date),
                        xmlelement(name "content", o.content)))),
       xmlelement(name "Payments",                          
             xmlagg(xmlelement(name "Payment",
                        xmlelement(name "id", p.id),                        
                        xmlelement(name "date", p.date),
                        xmlelement(name "amount", p.amount)))))
from customers c
left join orders o on c.id = o.c_id
left join payments p on c.id = p.c_id
group by c.id, c.name;

......没有意义。如果客户有5个订单和3个付款,它返回15行的表。所以有15个订单和15个付款。我不知道如何以正确的方式使用xmlaagg()函数。作为使用XML的完全新手,我甚至不知道是否可以以所需的方式从数据库创建输出。

我真的很感激任何帮助。

示例数据: (这只是一个简单的例子。假设订单和付款之间没有任何关系。在我的真实项目中还有其他项目,它们没有任何关系。我需要查看所有付款和所有订单。)

CREATE TEMPORARY TABLE customers
(
    id      int,
    name    text
);

CREATE TEMPORARY TABLE orders
(
    id      int,
    c_id    int, -- customer ID
    date    date,
    content text

);

CREATE TEMPORARY TABLE payments
(
    id      int,
    c_id    int, -- customer ID
    date    date,
    amount  numeric
);

INSERT INTO customers
VALUES(1, 'someguy');

INSERT INTO orders
VALUES
(1, 1, '1.1.2001', 'noteboook'),
(2, 1, '2.1.2001', 'tablet'),
(3, 1, '3.1.2001', 'phone'),
(4, 1, '3.1.2001', 'bag'),
(5, 1, '3.1.2001', 'shoes');

INSERT INTO payments
VALUES
(1, 1, '1.2.2001', '100'),
(2, 1, '2.2.2001', '200'),
(3, 1, '3.2.2001', '300');  

-- DROP TABLE payments;
-- DROP TABLE orders;
-- DROP TABLE customers;

1 个答案:

答案 0 :(得分:0)

必须在加入

之前进行聚合
select
    xmlelement(name "Customer",
        xmlelement(name "Name", name),
        orders, payments
    ) as the_xml
from
    customers
    left join (
        select c_id as id,
        xmlelement(name "Orders",
            xmlagg(xmlelement(name "Order",
                xmlelement(name "id", id),                    
                xmlelement(name "date", date),
                xmlelement(name "content", content)
                )
            )
        ) as orders
        from orders
        group by c_id
    ) o using (id)
    left join (
        select c_id as id,
        xmlelement(name "Payments",                          
            xmlagg(xmlelement(name "Payment",
                xmlelement(name "id", id),                        
                xmlelement(name "date", date),
                xmlelement(name "amount", amount)
                )
            )
        ) as payments
        from payments
        group by c_id
    ) p using (id)