mike16889
mike16889

Reputation: 352

MySQL left join with LIMIT 1 not returning desired result

I am having trouble with a SQL query; I am trying to get the last service date of each 'asset'.

I am trying to use a left join with a subquery with a limit to 1.

Here are my tables:

lctn_test

testID, cleintID
1,      34
2,      34

srvc_test

srvcTestID, testID, serviceDate,            servicePassed
1,          1,      2018-05-19 03:23:53,    1
2,          1,      2018-05-19 11:46:49,    1
3,          2,      2018-05-19 11:47:24,    1

and here is what I have tried (as well as a few variations)

SELECT 
    lctn.testID AS assetID, lctn.ClientID, 
    srvc_test.serviceDate, srvc_test.servicePassed
FROM 
    lctn_test AS lctn
LEFT JOIN 
    srvc_test ON lctn.testID = (SELECT srvc_test.testID
                                FROM srvc_test
                                WHERE srvc_test.testID = lctn.testID
                                ORDER BY srvc_test.serviceDate DESC
                                LIMIT 1)
WHERE 
    lctn.ClientID = 34
ORDER BY 
    assetID

What I expected to get:

assetID,    ClientID,   serviceDate,            servicePassed
1,          34,         2018-05-19 11:46:49,    1
2,          34,         2018-05-19 11:47:24,    1

but this is what I actually get:

assetID,    ClientID,   serviceDate,            servicePassed
1,          34,         2018-05-19 03:23:53,    1
1,          34,         2018-05-19 11:46:49,    1
1,          34,         2018-05-19 11:47:24,    1
2,          34,         2018-05-19 03:23:53,    1
2,          34,         2018-05-19 11:46:49,    1
2,          34,         2018-05-19 11:47:24,    1

I am still learning SQL (mysql) and for the life of me I can't see the issue; I am betting it is a noob mistake but I just don't see it.

Upvotes: 0

Views: 4977

Answers (3)

MatBailie
MatBailie

Reputation: 86715

You have a LEFT JOIN b ON a.id = (sub-query)

You should have a LEFT JOIN b ON b.id = (sub-query)

SELECT lctn.testID AS assetID, lctn.ClientID, srvc_test.serviceDate, srvc_test.servicePassed
FROM lctn_test AS lctn
LEFT JOIN srvc_test ON srvc_test.srvcTestID = (
    SELECT srvc_test.srvcTestID
    FROM srvc_test
    WHERE srvc_test.testID = lctn.testID
    ORDER BY srvc_test.serviceDate DESC
    LIMIT 1)
WHERE lctn.ClientID = 34
ORDER BY assetID

Upvotes: 2

Paul Spiegel
Paul Spiegel

Reputation: 31792

If you want exactly one row per join you should use a UNIQUE (or PRIMARY) KEY of the joined table in the ON clause. That is probably srvc_test.srvcTestID.

SELECT lctn.testID AS assetID, lctn.ClientID, srvc_test.serviceDate, srvc_test.servicePassed
FROM lctn_test AS lctn
LEFT JOIN srvc_test ON srvc_test.srvcTestID = (
    SELECT srvc_test.srvcTestID
    FROM srvc_test
    WHERE srvc_test.testID = lctn.testID
    ORDER BY srvc_test.serviceDate DESC
    LIMIT 1)
WHERE lctn.ClientID = 34
ORDER BY assetID

Upvotes: 1

Gordon Linoff
Gordon Linoff

Reputation: 1269853

Your query is missing the actual join condition:

SELECT lctn.testID AS assetID, lctn.ClientID, srvc_test.serviceDate, srvc_test.servicePassed
FROM lctn_test lctn LEFT JOIN
     srvc_test st
     ON st.testID = lctn.testID AND
        st.testID = (SELECT st2.testID
                     FROM srvc_test st2
                     WHERE st2.testID = st.testID
                     ORDER BY st.serviceDate DESC
                     LIMIT 1
                    )
WHERE lctn.ClientID = 34
ORDER BY assetID;

I switched the correlation conditions to be based on srvc_test rather than lctn_test. This doesn't really make a difference. I just find it simpler to be referring to a single table for this purpose.

Upvotes: 0

Related Questions