Home > Software design >  MySQL inner join limit 1 row from second table
MySQL inner join limit 1 row from second table

Time:10-21

I have 2 (MySQL) tables , exchange table can have 1--n rows in exchitems, when an exchange record has multiple rows, I would like to display the word "multi", but when there is only 1 row, I would like to display the row's details:

First table (exchange):

xid (PK) | cusid | xdate      | xref   | xtotal
1        | 1     | 2021-10-01 | 345667 | 500
2        | 1     | 2021-10-01 | 345668 | 200
3        | 1     | 2021-10-02 | 345669 | 450
4        | 1     | 2021-10-03 | 345670 | 1200

And the second table (exchitems):

chid (PK) | xid | cusid | xcur| xsell| xbuy
1         | 1   | 1     | USD | 300  | 0
2         | 1   | 1     | EUR | 0    | 400
3         | 2   | 1     | USD | 200  | 0
4         | 3   | 1     | EUR | 0    | 500
5         | 4   | 1     | EUR | 0    | 800
6         | 4   | 1     | USD | 300  | 0

The exchange table must have at least 1 row in exchtiems table, and this is what I would like to get:

xid | cusid | xdate      | xref   | xcur  | xsell | xbuy | xtotal
1   | 1     | 2021-10-01 | 345667 | multi | 0     | 0    | 500
2   | 1     | 2021-10-01 | 345668 | USD   | 200   | 0    | 200
3   | 1     | 2021-10-02 | 345669 | EUR   | 0     | 500  | 450
4   | 1     | 2021-10-03 | 345670 | multi | 0     | 0    | 1200

Using the following query, i am able to get the all records, but I would like to limit the exchitems table to one row "any row" when there are multiple rows, the count is used to display the word "multi" when it is > 1:

SELECT a.xid,a.xdate,a.xref,a.xtotal,b.xcur,b.xsell,b.xbuy,
(SELECT COUNT(*) FROM exchitems c WHERE c.xid= a.xid) AS tRec
FROM (exchange a 
INNER JOIN exchitems b ON a.xid= b.xid AND a.cusid= b.cusid)  
WHERE a.cusid = 1 
ORDER BY a.xdate DESC,a.xid DESC 

I have tried many different queries but couldn't achieve what I want.
Any help is highly appreciated.

CodePudding user response:

Untested, but this should work.

SELECT
    a.xid,
    a.cusid,
    a.xdate,
    a.xref,
    -- if distinct currency in the group is > 1 then the word 'multi', else currency.
    IF(COUNT(DISTINCT b.xcur) > 1, 'multi', b.xcur) AS `xcur`,
    b.xsell,
    b.xbuy,
    a.xtotal
FROM exchange a
JOIN exchitems b ON a.xid = b.xid AND a.cusid = b.cusid
WHERE a.cusid = 1
GROUP BY xid -- will let you have exchange rows with groups of exchitems 1:n
ORDER BY a.xdate DESC, a.xid DESC

CodePudding user response:

You can modify your current query to the following:

SELECT a.xid, a.cusid, a.xdate,
       a.xref,
       GROUP_CONCAT(b.xcur),
       MIN(b.xsell),
       MIN(b.xbuy),
       MAX(a.xtotal)
FROM (exchange a 
INNER JOIN exchitems b ON a.xid= b.xid AND a.cusid= b.cusid)  
WHERE a.cusid = 1 
GROUP BY a.xid,a.cusid,a.xdate,a.xref
ORDER BY a.xid;

The result will look like this:

xid cusid xdate xref GROUP_CONCAT(b.xcur) MIN(b.xsell) MIN(b.xbuy) MAX(a.xtotal)
1 1 2021-10-01 345667 USD,EUR 0 0 500
2 1 2021-10-01 345668 USD 200 0 200
3 1 2021-10-02 345669 EUR 0 500 450
4 1 2021-10-03 345670 EUR,USD 0 0 1200

The part where I use MIN and MAX is according to your expected result. You may want to clarify which value to show there is you have multiple value. If I change that to GROUP_CONCAT:

 SELECT a.xid, a.cusid, a.xdate,
        a.xref,
        GROUP_CONCAT(b.xcur),
        GROUP_CONCAT(b.xsell),
        GROUP_CONCAT(b.xbuy),
        GROUP_CONCAT(a.xtotal)
 FROM (exchange a 
 INNER JOIN exchitems b ON a.xid= b.xid AND a.cusid= b.cusid)  
 WHERE a.cusid = 1 
 GROUP BY a.xid,a.cusid,a.xdate,a.xref
 ORDER BY a.xid;

Then you'll see a more elaborate result:

xid cusid xdate xref GROUP_CONCAT(b.xcur) GROUP_CONCAT(b.xsell) GROUP_CONCAT(b.xbuy) GROUP_CONCAT(a.xtotal)
1 1 2021-10-01 345667 USD,EUR 300,0 0,400 500,500
2 1 2021-10-01 345668 USD 200 0 200
3 1 2021-10-02 345669 EUR 0 500 450
4 1 2021-10-03 345670 EUR,USD 0,300 800,0 1200,1200

To make the xcur value show multi, you probably can do something like:

SELECT a.xid, a.cusid, a.xdate,
       CASE WHEN COUNT(b.xcur) > 1 THEN 'multi' ELSE MAX(b.xcur) END AS xcur,
       MIN(b.xsell),
       MIN(b.xbuy),
       MAX(a.xtotal)
FROM (exchange a 
INNER JOIN exchitems b ON a.xid= b.xid AND a.cusid= b.cusid)  
WHERE a.cusid = 1 
GROUP BY a.xid,a.cusid,a.xdate,a.xref
ORDER BY a.xid;

Demo fiddle

  • Related