简体   繁体   中英

How to merge two tables with one to many relationship

I have two tables to main orders and ordered products.

Table 1: ORDERS
"CREATE TABLE IF NOT EXISTS ORDERS("
                       "id_order INTEGER PRIMARY KEY AUTOINCREMENT,
                       "o_date TEXT,"
                       "o_seller TEXT,"
                       "o_buyer TEXT,"
                       "o_shipping INTEGER,"
                       "d_amount INTEGER,"
                       "d_comm INTEGER,"
                       "d_netAmount INTEGER)"
Table 2: ORDERED_PRODUCTS
"CREATE TABLE IF NOT EXISTS dispatch_products("
                       "id_order INTEGER NOT NULL REFERENCES ORDERS(id_order),"
                       "product_name INTEGER,"
                       "quantity INTEGER,"
                       "rate INTEGER)"

I tried to join these two tables using following query:

SELECT *
FROM ORDERS a
INNER JOIN ORDERED_PRODUCTS b
ON a.id_order = b.id_order
WHERE a.buyer = 'abc'

The issue is with the entries with multiple products in table 2. The output I'm getting is like below:

order_ID date seller buyer Ship   amt  comm nAmt Prod  Qty Rate
1             A      x       5    100  5    115  Scale 10  10
2             B      abc     10   100  5    115  pen    5  10
2             B      abc     10   100  5    115  paper 10   5
3             C      xyz     10   100  5    220  book   5  20
3             C      xyz     10   100  5    220  stapl 10  10

expected output:
order_ID date seller buyer Ship   amt  comm nAmt Prod  Qty Rate
1             A      x       5    100  5    115  Scale 10  10
2             B      abc     10   100  5    115  pen    5  10
                                                 Paper 10   5
3             C      xyz     10   100  5    220  Book   5  20
                                                 Stapl 10  10

Databases don't really work like that; you got what you asked for, and with no duplicates (all rows are different). You're looking at the columns of data that came from orders and saying "oh, the data is duplicated" but it isn't - it's joined "in context"

Imagine I gave you just one of your sample rows from your expected output:

                                             Paper 10   5

Promise I just copy pasted that.

What order is it from?

No idea.. You've lost the context, so it could be from any order. Rows are individual entities, that stand alone and without reference to any other row, as a set of data. This is why the same order info needs to appear on each row. A database could be made to produce the expected output you asked for, but it would be really quote complex in a low end database like sqlite. More important to me is to point out why there's a difference between what you thought the query would give you, and what it gave you, as I think that's the real problem: the query gave you what it was supposed to, there's no fault in it; it's more a faulty assumption of what you'd get

If you're trying to prepare a report that uses the order as some kind of header, select them individually in the front end app. Select ALL the orders, then one by one (order by order) pull all the item detail out, building the report as you go:

myorders = dbquery("SELECT * FROM ORDERS")
for each(order o in myorders)
  print(o.header)
  details = dbquery("SELECT * FROM dispatch_products where id_order = ?", o.id)
  for each(detail d in details)
    print(d.prod, d.qty, d.rate)

Here's a way to make the DB do it, but you'll need a version of SQLite that supports window functions (3.10 doesn't) or another db (SQLS > 2008, Oracle > 9, or other big-name db from the last 10 or so years, or a very recent MySQL):

SELECT 
  CASE WHEN rn = 1 THEN d.o_date END as o_date,
  CASE WHEN rn = 1 THEN d.o_seller END as o_seller,
  CASE WHEN rn = 1 THEN d.o_buyer END as o_buyer,
  CASE WHEN rn = 1 THEN d.o_shipping END as o_shipping,
  CASE WHEN rn = 1 THEN d.d_amount END as d_amount,
  CASE WHEN rn = 1 THEN d.d_comm END as d_comm,
  CASE WHEN rn = 1 THEN d.d_netAmount END as d_netAmount,
  d.name,
  d.qty,
  d.rate
FROM
  SELECT o.*, op.name, op.qty, op.rate, row_number() over(partition by o.id_order order by op.name, op.qty, op.rate) rn
  FROM ORDERS o
  INNER JOIN ORDERED_PRODUCTS op
  ON o.id_order = op.id_order
  WHERE o.buyer = 'abc'
) d
ORDER BY d.id_order, d.rn

We basically take your query, add on a row number that restarts every time order id changes, and only show data from the orders table where rownumber is 1. If your SQLite doesn't have row_number you can fake it: How to use ROW_NUMBER in sqlite which i'll leave as an exercise for the reader :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM