简体   繁体   中英

SQL JOIN to Only One Row

I have 2 sale data tables that have no common keys, just sale date and customer name. I want to join them so that for each row from table A there will be at most 1 match from table B, or 0 if none is found. The problem is if the same customer shows up twice on the same date. So if I have data like these

Table A                             Table B

Customer | Date       | Receipt     Customer | Date       | Invoice
===============================     ===============================
John     | 2018-01-01 | A           John     | 2018-01-01 | C
John     | 2018-01-01 | B           John     | 2018-01-01 | D

How do I get this

Result

Customer | Date       | Receipt | Invoice
=========================================
John     | 2018-01-01 | A       | C
John     | 2018-01-01 | B       | D

It does not matter whether receipt A is matched with Invoice C or D, as long as each is paired once. Currently my query joins all of them, AC, AD, BC, BD

Edit: to clarify, I can't have duplicates from either table. One invoice and receipt can only appear once. So either one of these results are acceptable:

  • AC and BD
  • AD and BC

This is a pain, because you need to enumerate the two tables and then either join or aggregate. Here is one way:

select customer, date, max(receipt) as receipt, max(invoice) as invoice
from ((select a.customer, a.date, a.receipt,
              (@rnr := if(@cd = concat_ws(';', customer, date), @rnr + 1,
                          if(@cd := concat_ws(';', customer, date), 1, 1)
                         )
              ) as seqnum
       from a cross join
            (select @rnr := 0, @cd := '') params
       order by a.customer, a.date
      ) union all
      (select b.customer, b.date, b.invoice,
              (@rni := if(@cd = concat_ws(';', customer, date), @rni + 1,
                          if(@cd := concat_ws(';', customer, date), 1, 1)
                         )
              ) as seqnum
       from b cross join
            (select @rni := 0, @cd := '') params
       order by a.customer, a.date
      )
     ) cd
group by customer, date, seqnum;

Why not just do a distinct after you've joined your two tables since you only want distinct records?

SELECT DISTINCT a.Customer,
a.Date, 
a.Receipt, 
b.Invoice 
FROM Table_A a

JOIN Table_B b
ON a.Customer = b.Customer
AND a.Date = b.Date

I'm going to give an answer you're probably not going to like: this shouldn't be done in SQL. This is a presentation/display issue.

Do this sort of work in the layer that's displaying the data to the user, not the SQL back end. Are they looking it up in a web page? Then have the web page get the raw data and format it as needed - have it put the contents of each day's Receipts or each day's Invoices in separate divs. Is SQL sending out an email with this data? Then don't have it generate a plain-text email - have it generate HTML and put the data into table cells (so you don't have to coordinate rows between two sets of data with possibly differing amounts of data.)

You really don't want to be playing the game of trying to make SQL output look pretty from within SQL. Because, honestly, the code in the answer you've accepted may work correctly, but I'd hate to be trying to maintain it over the years...

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