Bogdan Bogdanov
Bogdan Bogdanov

Reputation: 992

MySQL query doesn't show results properly

I have 2 tables. One of my tables with users is:

id         name     longitude       latitutde  
-----      -----    -----------    -----------
1          Mark     -82.347036     29.6545095
2          John     -82.357036     29.665095
3          Paul     -82.367036     29.645095
4          Dave     -82.337036     29.675095
5          Chris    -82.437036     29.575095
6          Manny    -82.538036     29.745095
7          Fred     -82.638036     29.346095

I'm using SQL to detect nearby people:

 SELECT id, 
        ( 3959 * acos( cos( radians(37) ) * cos( radians( latitude ) ) *
             cos( radians( longitude ) - radians(-122) ) +
              sin( radians(37) ) * sin(radians(latitude)) ) 
             ) AS distance
    FROM `users` HAVING distance < 50 ORDER BY distance DESC LIMIT 20`

The other matches is like this:

id         sender    receiver        status  
-----      -----    -----------    -----------
1            3           4              0
2            1           5              1
3            6           3              1
4            2           6              0
5            2           1              0

Where sender is the person who sent the invitation receiver is the person who receives is.

My Query:

SELECT
a.id
,a.distance
FROM
  (Select  
       id,
       st_distance_sphere(POINT(-82.337036, 29.645095 ),
                          POINT(`longitude`, `latitude` ))/1000  as distance
    FROM
        users u  
    WHERE id <> 1 
    HAVING distance < 5000 
    ORDER BY distance 
    DESC LIMIT 20) a
WHERE
    a.id in (SELECT `sender` FROM matches WHERE status = 1)
    OR a.id NOT IN ( SELECT `sender` FROM matches
           UNION ALL SELECT `receiver` FROM matches )
ORDEr BY a.distance ASC

My fiddle: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=95972531a390a013796ed4cf7ad99884

In matches table Id 1 have match only with Id 5 (where status is 1).

The part with:

       a.id     in ( SELECT `sender` FROM matches WHERE status = 1)
    OR a.id NOT IN ( SELECT `sender` FROM matches
           UNION ALL SELECT `receiver` FROM matches )

is wrong somewhere, because it has to show id 2,3,4,6,7 not only 6 & 7 . Check out last query in fiddle

The query must be with logic:

If I am the sender with id 1 don't return me receiver(a.id).

If I'm receiver with id 1 return me sender(a.id) where status = 0.

If I'm not sender or receiver return me a.id

Upvotes: 0

Views: 234

Answers (2)

nbk
nbk

Reputation: 49373

When I use your logic

You want:

SELECT 
    a.id, a.distance
FROM
    (SELECT 
        id,
            ST_DISTANCE_SPHERE(POINT(- 82.337036, 29.645095), POINT(`longitude`, `latitude`)) / 1000 AS distance
    FROM
        users u
    WHERE
        id <> 1
    HAVING distance < 5000
    ORDER BY distance DESC
    LIMIT 20) a
WHERE
    a.id NOT IN (SELECT `sender` FROM (SELECT `sender` FROM matches UNION  SELECT `receiver` FROM matches) t1
WHERE `sender` IN (SELECT `sender` FROM matches WHERE `receiver` = 1 AND status = 1
UNION SELECT `receiver` FROM matches WHERE `sender`  = 1
))
ORDER BY a.distance ASC
id |           distance
:- | -----------------:
3  | 2.8991986256467865
2  |  2.946298180421104
4  |  3.335840468953696
7  |  44.20441197234838

db<>fiddle here

Upvotes: 2

Rick James
Rick James

Reputation: 142208

   a.id     in ( SELECT `sender` FROM matches WHERE status = 1)
OR a.id NOT IN ( SELECT `sender` FROM matches
       UNION ALL SELECT `receiver` FROM matches )

The first part of the OR gets ids senders, hence ids, 1 and 6.

But the second part is even more incriminating.

SELECT `sender` FROM matches    -- 1,2,2,3,    6
UNION ALL 
SELECT `receiver` FROM matches  -- 1,    3,4,5,6

The UNION ALL is 1,1,2,2,3,3,4,5,6,6.

The dups are ignored.

Meanwhile, a.id is some subset of 1,2,3,4,5,6,7, depending on the distance arithmetic. Hence the only a.id left from the second part of the OR is 7.

So, I would expect to get 1, 6, and maybe 7.

Hmmm... I think I am getting lost, and I think you were getting lost. Please change things so that there are not two ids, and 4 meanings of 1. 1 as a status, 1 as a sender/receiver, 1 as two different ids. For example, make the matches.id between 11 and 16; make all the senders/receivers between 21 and 27. Make the statuses ON and OFF (or something).

Upvotes: 1

Related Questions