连接两个一对多表会重复记录

时间:2018-10-08 22:57:55

标签: postgresql postgresql-9.4

我有3张桌子Transaction, Transaction_Items and Transaction_History

其中Transaction是父表,而Transaction_Items and Transaction_History是子表,其中one to many relationship

当我尝试将这些表连接在一起时,如果我有2+ Transaction_History条记录或2+ Transaction_Items,则会得到重复或重复的记录结果。

这是当前正在使用的SQL查询,该查询有效,但令我担心的是,如果将来我必须联接另一个one-to-many表,它将再次复制结果。

我找到了解决方法,但是我只是想知道是否有更好,更清洁的方法来做到这一点?

  

结果应为PostgreSQL JSON数组,其中将包含Transaction_Items和Transaction_History

SELECT
    TR.id AS transaction_id,
    TR.transaction_number,
    TR.status,
    TR.status AS status,
    to_json(TR_INV.list),
    COUNT(TR_INV) item_cnt,
    COUNT(THR) tr_cnt,
    json_agg(THR)
FROM transaction_transaction AS TR
LEFT JOIN (
    SELECT
        array_agg(t) list, -- this is a workaround method
        t.transaction_id
    FROM (
        SELECT
            TR_INV.transaction_id      transaction_id,
            IT.id,
            IT.stock_number,
            CAT.key                    category_key,
            ITP.description            description,
            ITP.serial_number          serial_number,
            ITP.color                  color,
            ITP.manufacturer           manufacturer,
            ITP.inventory_model        inventory_model,
            ITP.average_cost           average_cost,
            ITP.location_in_store      location_in_store,
            ITP.firearm_caliber        firearm_caliber,
            ITP.federal_firearm_number federal_firearm_number,
            ITP.sold_price             sold_price
        FROM transaction_transaction_item TR_INV
            LEFT JOIN inventory_item IT ON IT.id = TR_INV.item_id
            LEFT JOIN inventory_itemprofile ITP ON ITP.id = IT.current_profile_id
            LEFT JOIN inventory_category CAT ON CAT.id = ITP.category_id
            LEFT JOIN inventory_categorytype CAT_T ON CAT_T.id = CAT.category_type_id
    ) t
    GROUP BY t.transaction_id
) TR_INV ON TR_INV.transaction_id = TR.id
LEFT JOIN transaction_transactionhistory THR ON THR.transaction_id = TR.id
    AND (THR.audit_code_id = 44 OR THR.audit_code_id = 27 OR THR.audit_code_id = 28)
WHERE TR.store_id = 21
    AND TR.transaction_type = 'Pawn_Loan' AND TR.date_made >= '2018-10-08'
GROUP BY TR.id, TR_INV.list

1 个答案:

答案 0 :(得分:0)

您可以通过不使用联接来实现,如下所示。 因为您的实际表有很多列,我不知道也不应该在乎。我只是创建了其中最简单的形式进行演示。

CREATE TABLE transactions (
     tid    serial PRIMARY KEY,
     name   varchar(40) NOT NULL 
);

CREATE TABLE transaction_histories (
     hid    serial PRIMARY KEY ,
     tid    integer REFERENCES transactions(tid),
     history   varchar(40) NOT NULL 
);

CREATE TABLE transaction_items (
     iid    serial PRIMARY KEY ,
     tid    integer REFERENCES transactions(tid),
     item   varchar(40) NOT NULL 
);

INSERT INTO transactions(tid,name) Values(1, 'transaction');

INSERT INTO transaction_histories(tid, history) Values(1, 'history1');
INSERT INTO transaction_histories(tid, history) Values(1, 'history2');

INSERT INTO transaction_items(tid, item) Values(1, 'item1');
INSERT INTO transaction_items(tid, item) Values(1, 'item2');


select
t.*,

(select count(*) from transaction_histories h where  h.tid= t.tid) h_count ,
(select json_agg(h) from transaction_histories h where  h.tid= t.tid) h ,

(select count(*) from transaction_items i where  i.tid= t.tid) i_count ,
(select json_agg(i) from transaction_items i where  i.tid= t.tid) i

from transactions t;