In the following db, I need all users and their locations, without duplicates, and with those in NJ listed first.
(If they have a NJ address, I do not need their other addresses. Database simplified for clarity).
> table address,
| id | state | City |
|------|--------|----------|
| 01 | NY | Gotham |
| 02 | NY | Uye |
| 03 | NJ | Hoboken |
| 04 | NJ | Newark |
> table contact
| user | address |
|--------|-----------|
| 01 | 01 |
| 02 | 02 |
| 02 | 03 |
| 03 | 04 |
Below are some of my attempts and their outputs.
From what I have read [I have spent hours on this], I think this is called a ambiguous GROUP BY query, and is only allowed by MySQL.
I can’t figure out the correct way to do this, though. Please help!
DESIRED RESULT:
| user | state |
|--------|---------|
| 02 | NJ |
| 03 | NJ |
| 01 | NY |
OTHER ATTEMPTS:
SELECT user, state FROM contact, address WHERE id = address;
// Duplicate users, and addresses I do not need.
| user | state |
|--------|---------|
| 01 | NY |
| 02 | NY |
| 02 | NJ |
| 03 | NJ |
SELECT user, state FROM contact, address WHERE id = address GROUP BY user;
// NY address. I need the NJ address.
| user | state |
|--------|---------|
| 01 | NY |
| 02 | NY |
| 03 | NJ |
SELECT user, state FROM contact, address WHERE id = address GROUP BY user HAVING state = 'NJ';
//Worse, now I lose my NY users, and one of my NJ users doesn't even show
| user | state |
|--------|---------|
| 03 | NJ |
It may not be pretty, but this solution works. I’ve updated the query here to reflect changes in the fiddle:
Simple explanation: Join every user with his address where the address is in NJ or with any address of his if he has no addresses in NJ. The GROUP BY is needed to prevent duplicate users from showing up in the results.
Essentially what the problem boils down to is wanting to retrieve a matching address for a user if it exists, and otherwise just to get any address for that user. Thus the second condition in the where clause, which will pull an NJ address only if that user has one, otherwise it will just take the first normally. The ismatch field is for sorting purposes.
Note: I originally wrote this using JOINs between the tables. They have been removed for clarity purposes.
Link to SQL Fiddle
EDIT: It was pointed out to me that this solution does not work in all cases (see comments). To fix this, I added a GROUP BY, and now it appears to work. I also replaced the CASE with a simple comparison to improve performance: SQLFiddle
In addition, an alternate answer has been suggested to me by someone I know with experience in database management. His suggestion wast to do it in two queries (at least), so I built those queries and used a UNION:
Simple Explanation: Fetch every user with an NJ address, then fetch every user with any address if he has no NJ addresses, and UNION the two result sets together. GROUP BY is used in both queries to prevent duplicates.